給定以下代碼,為什么 Typescript 在getInferred方法中出錯?是否存在不同的ValueOf<this>情況T?
interface Wrapper<T> {
value: T;
}
type ValueOf<T> = T extends Wrapper<infer U> ? U : never;
class Foo<T> implements Wrapper<T> {
value: T;
constructor(value: T) {
this.value = value;
}
getInferred = (): ValueOf<this> => {
// Type 'T' is not assignable to type 'GetGeneric<this>'.
return this.value;
}
getSimple = (): T => {
// Works Fine
return this.value;
}
}
對于我的用例,我正在向類動態添加方法,并ValueOf<this>為動態方法提供更好的回傳型別。
const mixin = {
getFooInferred<Self extends Foo<any>>(this: Self) {
return this.getInferred();
},
getFooSimple<Self extends Foo<any>>(this: Self) {
return this.getSimple();
}
}
function makeFooWithMixin<T>(value: T) {
const foo = new Foo(value);
Object.defineProperties(foo, {
getFooInferred: {
value: mixin.getFooInferred,
},
getFooSimple: {
value: mixin.getFooSimple,
}
});
return foo as Foo<T> & typeof mixin;
}
const foo = makeFooWithMixin("hello")
// When using the returntype of `getInferred`, we correctly get `string` as the type here
const resultInferred = foo.getFooInferred()
// When using `getSimple`, we instead get `any` because `getFooSimple` types the `Self` generic as `Foo<any>`
const resultSimple = foo.getFooSimple();
以上所有代碼的打字稿游樂場鏈接
uj5u.com熱心網友回復:
多態this型別被實作為所有類和介面都具有的隱式泛型型別引數(請參閱microsoft/TypeScript#4910)。而你的ValueOf<T>型別,定義為
type ValueOf<T> = T extends Wrapper<infer U> ? U : never;
是條件型別。依賴于泛型型別引數ValueOf<this>的條件型別也是如此。
不幸的是,TypeScript 編譯器無法對可以分配給這種型別的值進行太多推理。它推遲了對型別的評估,并且只有在指定后才能知道它的真正含義this,例如在 callnew Foo("x").getInferred()中, where thiswill be Foo<string>。在 , 的主體內部getInferred()是this未指定的(它可以是 的任何子型別Foo<T>),因此對于編譯器ValueOf<this>來說本質??上是不透明的。不是 thatthis.value可以是 以外的型別ValueOf<this>,而是編譯器看不到它。它將拒絕任何尚未屬于 type 的值ValueOf<this>。
如果您使用類似的型別斷言this.value as ValueOf<this>,那么編譯器將允許您回傳它,但這只是因為您聲稱它this.value是 type ValueOf<this>,而不是因為編譯器可以以一種或另一種方式告訴您:
getInferred = (): ValueOf<this> => {
return this.value as ValueOf<this>; // okay
}
一般來說,如果你需要提供一個泛型條件型別的值,你將不得不做一些不安全的事情,比如型別斷言。但在這種特殊情況下,你有一個選擇。您所做的ValueOf<T>只是查找value-keyed 中的屬性T。這可以在沒有條件型別的情況下完成。您可以改用索引訪問型別:
type ValueOf<T extends Wrapper<any>> = T['value']
即使編譯器仍然不能很好地理解泛型型別的任意操作,它確實知道如果你有一個型別的值T和一個型別的鍵,K那么你在該鍵上讀取的屬性值將是 type T[K],即使T或者K是通用的。所以它應該能夠驗證它this.value的型別this["value"]:
getInferred = (): ValueOf<this> => {
return this.value; // okay
}
確實可以。
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/474115.html
