我們想在超類上創建一個泛型方法,該方法接受一個參數,該參數是子類上某一類型的任何屬性的名稱。考慮一下這個(非常做作的)例子:
class CanUpcase {
upcase<PropertyName extends keyof this>(
propertyName: this[PropertyName] extends string ? PropertyName : never
) {
return this[propertyName].toUpperCase(); // Property 'toUpperCase' does not exist on type 'this[this[PropertyName] extends string ? PropertyName : never]'.
}
}
class User extends CanUpcase {
age = NaN;
name = ``;
constructor() {
super();
this.upcase('name'); // Argument of type '"name"' is not assignable to parameter of type 'this["name"] extends string ? "name" : never'.ts(2345)
}
}
const user = new User();
user.upcase('name'); // No error
我們預期upcase
會接受'name'
,因為'name'
屬性是一個字符串。
然而,當user.upcase('name')
按預期工作時,this.upcase('name')
拋出了一個錯誤,如圖所示。
此外,在upcase
內,this[propertyName]
不被識別為字符串。
- 為什么
this.upcase
拋出錯誤而不是user.upcase
? - 為什么
this[propertyName]
不被識別為字符串?
Thanks!
關鍵問題在于這條線:
盡管我們將propertyName限制為僅包含[propertyName]為字符串的鍵,但TypeScript不會將此約束應用于此[propertyName]的解析類型。這是由于使用條件類型時TypeScript的類型推理限制造成的。
解決方案:使用顯式泛型約束