簡體   English   中英

為什么這種映射/條件類型在推斷“this”的類型與明確接收它時的行為方式不同?

[英]Why does this mapped/conditional type behave differently when inferring the type of “this” vs receiving it explicitly?

請考慮以下代碼,該代碼使用v2.8中引入的 TypeScript語言功能(條件類型):

type P<TObject, TPropertySuperType> = {
    [K in keyof TObject]: TObject[K] extends TPropertySuperType ? K : never;
}[keyof TObject];

function g<
    T,
    K extends keyof Pick<T, P<T, string>>
    >(obj: T, prop: K): void { }

class C {
    public alpha: string;
    public beta: number;

    public f(): void {
        g(this, "alpha"); // <-- does not compile!
        g(this, "beta");

        g<C, "alpha">(this, "alpha");
        g<C, "beta">(this, "beta");

        g(new C(), "alpha");
        g(new C(), "beta");

        this.g2("alpha");
        this.g2("beta");

        this.g2<"alpha">("alpha");
        this.g2<"beta">("beta");
    }

    public g2<
        K extends keyof Pick<C, P<C, string>>
        >(prop: K) { }
}

類型P背后的想法是它選擇TObject屬性的名稱 ,以滿足屬性類型擴展TPropertySuperType的約束。 然后函數gg2在類型參數約束中使用類型P ,這樣:

  • prop參數是objextends string -typed屬性的名稱時,您只能調用g
  • prop參數是Cextends string -typed屬性的名稱時,您只能調用g2

在這里,因為C.alphastring類型而C.beta是類型number ,我希望所有五個調用g / g2prop === "alpha"進行編譯,並且所有五個調用都使用prop === "beta" 編譯。

然而,調用g(this, "alpha") 進行編譯,因為你可以看到,如果你的代碼粘貼到的打字稿操場 錯誤是:

Argument of type '"alpha"' is not assignable to parameter of type 'this[keyof this] extends string ? keyof this : never'.

為什么這個特定的調用失敗了? 我猜它是與打字稿如何推斷的類型this ,但細節模糊了我。

我同意arthem最有可能的罪魁禍首是多態的this 雖然明顯的類型, this將是多態的this 雖然你可以肯定地說C['alpha']string類型,對於this['alpha']你不能這么說,你只能說this['alpha'] extends string了一個更復雜的this['alpha'] extends string編譯器的關系。 不確定這個比喻是否有幫助,但多態this就像一個類的隱藏類型參數,並且使用它受到類似的限制。 例如,在g內部,由於泛型類型參數的限制, obj['prop']類型不再是string

function g<
    T,
    K extends keyof Pick<T, P<T, string>>
    >(obj: T, prop: K): void {  obj[prop].charAt(0) /*error*/}

雖然上述猜測(我得承認有點模糊),即解決了上述錯誤的解決方案將解決這個問題this就是把我們的約束,只有string鍵可以以不同的方式傳遞英寸

function g3<
    K extends string | number | symbol,
    T extends Record<K, string>
    >(obj: T, prop: K): void {   obj[prop].charAt(0) /* ok*/ }

class C {
    public alpha!: string;
    public beta!: number;

    public f(): void {
        g3(this, "alpha"); // also ok as expected
        g3(this, "beta"); //not ok
    }
}

這很難說,不看編譯器源,但有一點是明確的: this里面C沒有類型C ,基於這樣的觀察是錯誤消失,如果你添加一個類型斷言this as C

class C {
    public alpha: string;
    public beta: number;

    public f(): void {
        g(this as C, "alpha"); // ok

this[keyof this]的類型在TObject[K]的錯誤消息中拼寫出來,暗示this“多態這個”類型 - 代表C所有可能子類型的類型。

我不知道是什么原因導致this被視為多態(也許它總是被認為是多態的),但它有一個令人遺憾的結果,它的鍵集並不是靜態知道的。

雖然可以證明即使具有多態性, "alpha"也總是在其鍵中,並且this["alpha"]類型將與string兼容,因為它在C聲明,編譯器不遵循必要的邏輯,並且只是玩得安全 - “如果它不是靜態知道它是不相容的”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM