TypeScript - 安全導航運算子 (?.) 或 (!.) 以及空屬性路徑
在 Angular 2 模板中,安全操作符 ?. 可以使用,但在使用 TypeScript 2.0 的 component.ts 中則無法使用。同時,安全導覽操作符 (!.) 也無法使用。
例如:
這個 TypeScript
if (a!.b!.c) { }
編譯成這個 JavaScript
if (a.b.c) { }
但是當我運行它時,我收到以下錯誤:
無法讀取未定義的屬性 'b'
有其他替代方案嗎?
if (a && a.b && a.b.c) { }
答案#1
! 是非空斷言運算子(後綴表達式)——它只是告訴類型檢查器,你確定 a 不是 null 或 undefined。
操作
a!會產生一個類型為a的值,並排除null和undefined
可選鏈接終於來到 TypeScript (3.7) 🎉
可選鏈接運算子
?.允許讀取位於連接物件鏈中深層的屬性值,而無需明確驗證鏈中每個引用是否有效。?.運算子的功能類似於.鏈接運算子,不同之處在於,如果引用為無效值(null或undefined),它不會引發錯誤,而是短路並返回undefined。當與函數調用一起使用時,如果指定的函數不存在,它會返回undefined。
語法:
obj?.prop // Accessing object's property
obj?.[expr] // Optional chaining with expressions
arr?.[index] // Array item access with optional chaining
func?.(args) // Optional chaining with function calls
注意:
在賦值的左側使用可選鏈接是無效的
const object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
答案#2
自從 TypeScript 3.7 發布以來,你現在可以使用可選鏈接了。
屬性範例:
let x = foo?.bar.baz();
這等同於:
let x = (foo === null || foo === undefined)
? undefined
: foo.bar.baz();
此外你可以撥打:
可選通話
function(otherFn: (par: string) => void) {
otherFn?.("some value");
}
otherFn 只有在 otherFn 不等於 null 或 undefined 時才會被呼叫
在 IF 條件語句中使用可選鏈結
這個:
if (someObj && someObj.someProperty) {
// ...
}
現在可以用這個替換
if (someObj?.someProperty) {
// ...
}
參考資料:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html
答案#3
更新:
計劃於 3.7 版本範圍內發佈
https://github.com/microsoft/TypeScript/issues/33352
你可以嘗試寫一個像那樣的自訂函數。
這種方法的主要優勢是類型檢查和部分智慧感知。
export function nullSafe<T,
K0 extends keyof T,
K1 extends keyof T[K0],
K2 extends keyof T[K0][K1],
K3 extends keyof T[K0][K1][K2],
K4 extends keyof T[K0][K1][K2][K3],
K5 extends keyof T[K0][K1][K2][K3][K4]>
(obj: T, k0: K0, k1?: K1, k2?: K2, k3?: K3, k4?: K4, k5?: K5) {
let result: any = obj;
const keysCount = arguments.length - 1;
for (var i = 1; i <= keysCount; i++) {
if (result === null || result === undefined) return result;
result = result[arguments[i]];
}
return result;
}
以及用法(支援最多 5 個參數,且可擴展):
nullSafe(a, 'b', 'c');
操場上的範例。
答案#4
另一個使用外部函式庫的替代方法是來自 Lodash 的 _.has()。
例如
_.has(a, 'b.c')
等於
(a && a.b && a.b.c)
編輯:如評論中所指出的,使用這種方法時,你會失去 Typescript 的類型推斷。例如,假設某人的物件已正確定義類型,如果 z 不是物件 b 的字段,使用 (a && a.b && a.b.z) 會得到編譯錯誤。但使用 _.has(a, 'b.z'),就不會出現該錯誤。
