網站搜尋

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'),就不會出現該錯誤。