![](/img/trans.png)
[英]Why do type guards behave differently when using Partial mapped types in TypeScript
[英]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
的約束。 然后函數g
和g2
在類型參數約束中使用類型P
,這樣:
prop
參數是obj
的extends string
-typed屬性的名稱時,您只能調用g
prop
參數是C
的extends string
-typed屬性的名稱時,您只能調用g2
。 在這里,因為C.alpha
是string
類型而C.beta
是類型number
,我希望所有五個調用g
/ g2
與prop === "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.