這最好用一個例子來解釋。我需要在靜態方法中參考當前類,這按預期作業:
class Cls {
static fn<T extends typeof Cls>(
this: T,
arg: T extends typeof Cls ? true : false,
) {}
}
Cls.fn(true);
Cls.fn(false); // Argument of type 'false' is not assignable to parameter of type 'true'.
但是,當Cls.fn從另一個靜態方法呼叫時,它不起作用:
class Cls {
static fn1<T extends typeof Cls>(
this: T,
arg: T extends typeof Cls ? true : false,
) {}
static fn2<T extends typeof Cls>(this: T) {
this.fn1(true); // Argument of type 'true' is not assignable to parameter of type 'T extends typeof Cls ? true : false'.
}
}
TS游樂場
有趣的是,如果我洗掉fn2's generic 或 do ,它會起作用this.fn1<typeof Cls>(true)。這意味著錯誤與this. 我認為這與this參考的任何子類有關Cls,而不是完全Cls。但是,即使this是 的子類Cls,T extends typeof Cls仍然是正確的。
這是 Typescript 使用錯誤值的錯誤this嗎?如果它不是一個錯誤,我該如何修復它?
在我的實際代碼中,我需要參考當前類,因為該方法根據子類接受不同的引數。
編輯: 這是一個使用子類的更現實的例子
uj5u.com熱心網友回復:
該行為由未決議的泛型型別引數解釋。
這是由基本上是高階函式(方法)引入的間接引起的。在非泛型方法的情況下fn2(使用Sub/Base示例),推理按預期作業,因為型別引數typeof Sub在派生類中決議為Sub:
Base.fn<typeof Sub>(this: typeof Sub, arg: "sub"): void
不幸的是,在 的情況下fn3,它本身就是一個泛型函式(方法),導致T呼叫中的泛型引數無法fn決議,這可以從推斷的簽名中看出:
Base.fn<T>(this: T, arg: T extends typeof Sub ? "sub" : "base"): void
這清除了以下編譯器錯誤的含義 - 因為條件型別也未解決,也"sub"不能"base"分配給T extends typeof Sub ? "sub" : "base":
'"sub"' 型別的引數不能分配給 'T extends typeof Sub 型別的引數?“子”:“基地”'
正如您正確指出的那樣,可以洗掉高階方法的泛型型別引數,從而洗掉間接:
static fn3(this: typeof Sub) {
this.fn('base'); // error
this.fn('sub'); // OK
}
但是,如果您需要,這會給進一步的派生類帶來復雜性this:
class Sub {
static fn4(this: typeof Sub) {
this.fn('sub');
return this;
}
}
class SubSub extends Sub {}
SubSub.fn4(); // typeof Sub, probably wanted typeof SubSub
不過,還有另一種選擇——不要限制T引數,而是this根據T推斷的型別來限制型別。經典技術是使用決議為自身的條件型別never:
class Sub extends Base {
static fn3<T>(this: T extends typeof Sub? T: never) {
this.fn('base'); // error
this.fn('sub'); // OK
return this;
}
}
Sub.fn('sub'); // OK
Sub.fn('base'); // error
Sub.fn3(); // typeof Sub
內部this.fn()呼叫的簽名推斷為:
Base.fn<T extends typeof Sub ? T : never>(this: T extends typeof Sub ? T : never, arg: (T extends typeof Sub ? T : never) extends typeof Sub ? "sub" : "base"): void
通過進一步推遲評估,T extends typeof Sub ? T : never我們實際上幫助了編譯器:現在它T可以保證在typeof Sub實體化時是這樣。
操場
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/405266.html
標籤:
上一篇:使用泛型從串列中選擇最大值
