typescript - 如何获取泛型类的内部类型
假设我有以下代码:
interface Outer<T = any> {
name: string;
body: T;
}
interface MyClass<T extends Outer> {
myFunction2: typeof myFunction2;
};
class MyClass<T extends Outer> {
data: T;
myFunction1() {
return this.data.body;
}
}
MyClass.prototype.myFunction2 = myFunction2;
function myFunction2<T extends MyClass<Outer<R>>, R>(this: T): R {
return this.data.body;
}
如果我现在创建该类的一个实例并尝试直接访问 body 属性,它将按预期工作:
let myClass = new MyClass<Outer<number>>();
const direct = myClass.data.body; // number
但是如果我尝试通过一个函数访问该属性,我无法让它工作。
const f1 = myClass.myFunction1(); // is 'any' but expecting 'number'
const f2 = myClass.myFunction2(); // is '{}' but expecting 'number'
我如何才能让 TypeScript 了解内部类型(在此示例中 body 的类型)?我知道可以向 TypeScript 提供更多信息,例如:
const f2 = myClass.myFunction2<MyClass<Outer<number>>, number>(); // number
但那非常冗长,而且我会失去一些类型安全性。
问题:我能否以某种方式重写 MyClass,使 TypeScript 能够识别 myFunction1 和 myFunction2 的返回值?我主要关注如何解决 myFunction2(扩展原型)的情况,不过 myFunction1 也很有趣。
TypeScript playground 中的代码。
谢谢!
答案#1
我刚刚发现了 T['key'] 语法,它可以用来获取一个内部类型:
interface Outer<T = any> {
name: string;
body: T;
}
interface MyClass<T extends Outer> {
myFunction2: typeof myFunction2;
};
class MyClass<T extends Outer> {
data: T;
myFunction1(): T['body'] {
return this.data.body;
}
}
MyClass.prototype.myFunction2 = myFunction2;
function myFunction2<T extends Outer>(this: MyClass<T>): T['body'] {
return this.data.body;
}
所以现在我可以得到“内部”类型 🎉
let myClass = new MyClass<Outer<number>>();
const direct = myClass.data.body; // number
const f1 = myClass.myFunction1(); // number
const f2 = myClass.myFunction2(); // number
编辑:链接
答案#2
问题是,遗憾的是,TypeScript 无法在泛型类型中推断更深层的属性。它还会急切地解析类型变量,因此 myFunction1 的类型就好像 T 是 Outer。因此它的返回值是 any。你需要在 data 中显式地指定 body 属性的类型。
interface Outer<T = any> {
name: string;
body: T;
}
class MyClass<T> {
data: Outer<T>;
myFunction2: typeof myFunction2;
myFunction1() {
return this.data.body;
}
}
MyClass.prototype.myFunction2 = myFunction2;
function myFunction2<T extends MyClass<R>, R>(this: T): R {
return this.data.body;
}
let myClass = new MyClass<number>();
const direct = myClass.data.body; // number
const f1 = myClass.myFunction1(); // now is number
const f2 = myClass.myFunction2(); // still {}, due to inference constraint
const f3 = myClass.myFunction2<MyClass<number>, number>(); // number
链接
