TypeScript中条件类型内使用this类型失效?原因及解决方法
TypeScript中this类型与条件类型结合的问题及解决方法
问题描述
尝试在父类中通过this类型结合条件类型定义抽象变量,实现自动提取当前类中数值类型属性的子集,但在子类赋值时出现类型错误。
父类与类型定义
type NumberSubsets<Subset extends Car> = Record<{ [key in Exclude<keyof Subset, 'all_numbers'>]: Subset[key] extends number ? key : never; }[Exclude<keyof Subset, 'all_numbers'>], number>; abstract class Car { public abstract all_numbers: NumberSubsets<this>; public doors: number; public is_truck: boolean; public wheels: number; }
子类实现
class Sedan extends Car { public all_numbers: NumberSubsets<this>; constructor() { super(); this.all_numbers = { doors: 5, // 此处报错 wheels: 6 }; } }
错误信息
Type '{ doors: number; wheels: number; }' is not assignable to type 'NumberSubsets<this>'. Object literal may only specify known properties, and 'doors' does not exist in type 'NumberSubsets<this>'
已知NumberSubsets<Sedan>可以正常工作,但希望用this简化子类的类型定义,无需手动指定具体类名。
错误原因
这是因为多态this类型在条件类型中会被延迟解析。在子类Sedan的构造函数中,this代表当前类的实例,但TypeScript无法提前确定NumberSubsets<this>的具体结构——因为this还可能被更下层的子类继承,此时NumberSubsets<this>的结果会随子类扩展而变化。因此TypeScript无法在当前上下文推断出doors和wheels是NumberSubsets<this>的合法属性。
解决方案
可以通过给抽象类添加泛型参数,将当前类的类型显式传入,让TypeScript能提前解析NumberSubsets的具体结构:
修改后的父类与子类
type NumberSubsets<Subset extends Car<Subset>> = Record<{ [key in Exclude<keyof Subset, 'all_numbers'>]: Subset[key] extends number ? key : never; }[Exclude<keyof Subset, 'all_numbers'>], number>; abstract class Car<T extends Car<T>> { public abstract all_numbers: NumberSubsets<T>; public doors: number; public is_truck: boolean; public wheels: number; } class Sedan extends Car<Sedan> { public all_numbers: NumberSubsets<Sedan>; constructor() { super(); this.all_numbers = { doors: 5, wheels: 6 }; } }
简化子类写法(可选)
如果不想在子类中重复写NumberSubsets<Sedan>,可以在父类中把all_numbers的类型直接关联到泛型参数T,子类只需继承时传入自身类型即可:
type NumberSubsets<Subset extends Car<Subset>> = Record<{ [key in Exclude<keyof Subset, 'all_numbers'>]: Subset[key] extends number ? key : never; }[Exclude<keyof Subset, 'all_numbers'>], number>; abstract class Car<T extends Car<T>> { public abstract all_numbers: NumberSubsets<T>; public doors: number; public is_truck: boolean; public wheels: number; } class Sedan extends Car<Sedan> { public all_numbers = { doors: 5, wheels: 6 }; }
这样TypeScript会自动推断all_numbers的类型符合NumberSubsets<Sedan>的要求,同时保留了代码的简洁性。
内容的提问来源于stack exchange,提问作者Kyle
相关产品推荐
相关产品推荐

