網站搜尋

我如何在 TypeScript 中為返回的函數獲取類型安全?


這個 TypeScript 編譯沒問題:

abstract class Animal {
    /*
    Any extension of Animal MUST have a function which returns
    another function that has exactly the signature (string): void
     */
    abstract getPlayBehavior(): (toy: string) => void;
}

class Cat extends Animal {
    /*
    Clearly does not have a function which returns a function
    that has the correct signature. This function returns a function with
    the signature (void) : void
    */
    getPlayBehavior() {
        return () => {
            console.log(`Play with toy_var_would_go_here!`);
        };
    }
}

class Program {
    static main() {
        let cat: Animal = new Cat();
        cat.getPlayBehavior()("Toy");
    }
}

Program.main();

我預期會出現錯誤,因為 Cat 類別明顯沒有正確地實作抽象的 Animal 類別。我預期 Cat 類別必須有一個函數,該函數返回另一個具有抽象 Animal 類別中指定的完全相同簽名的函數。

執行程式碼後,我得到:

> node index.js
> Play with toy_var_would_go_here!

有什麼我可以做的來確保編譯器強制執行這種政策嗎?

答案#1

你沒有得到錯誤是因為在 JavaScript/TypeScript 中,如果你不想使用參數,你不必強制宣告它們,只要沒有矛盾。

例如,Array.forEach 的簽名是:

forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;

但是這樣編譯就沒問題了:

let a = [1, 2, 3];
a.forEach(item => console.log(item));

這是件好事,如果我必須擁有所有參數即使我不使用它們,那將會很糟糕。
這裡也是一樣的情況:

type MyFn = (s: string) => void;
let fn: MyFn = () => console.log("hey");

如果我不需要使用字串參數,那麼我可以忽略它,或者我甚至可以這樣做:

let fn: MyFn = () => console.log(arguments);

如果你將在 Cat.getPlayBehavior 中返回的函數的簽名更改為與 Animal 中的定義相矛盾的形式,則會出現錯誤:

class Cat extends Animal {
    getPlayBehavior() {
        return (n: number) => {
            console.log(`Play with toy_var_would_go_here!`);
        };
    }
}

錯誤:

Class 'Cat' incorrectly extends base class 'Animal'.
  Types of property 'getPlayBehavior' are incompatible.
    Type '() => (n: number) => void' is not assignable to type '() => (toy: string) => void'.
      Type '(n: number) => void' is not assignable to type '(toy: string) => void'.
        Types of parameters 'n' and 'toy' are incompatible.
          Type 'string' is not assignable to type 'number'.

答案#2

我預期會出現錯誤,因為 Cat 類別肯定沒有正確實作抽象的 Animal 類別

因為類型相容性。一個不接受任何參數的函數(例如 foo)可以被指派給一個接受參數的函數(例如 bar)。

原因:不存在 bar 的使用情況,在那裡 foo 運作所需的所有資訊將會缺失。

更多

這裡也有介紹:https://basarat.gitbooks.io/typescript/content/docs/types/type-compatibility.html#number-of-arguments