TypeScript多态this关键字在类方法内使用不符合预期如何解决
问题产生原因
多态this本质是类型层面的「子类实例占位符」,它的类型会跟随最终实例化的类(包括继承自Foo的子类)动态变化,而非固定为当前Foo类的类型。
TS抛出类型错误是出于类型安全考虑:假设存在Foo的子类重写了filteredAxis/filteredDirection属性的类型为非string[]类型(比如number[]),此时父类test方法的赋值操作就会出现类型不匹配。因此TS不会直接将this[filtered${string} & keyof this]推导为固定的string[]类型,也就不允许直接赋值string[]类型的值。
可行解决方案
- 方案1:类型断言(最简单,适合确定不会有子类重写filtered前缀属性类型的场景)
直接对赋值目标做类型断言即可:
class Foo { axisControl: string = "string"; directionControl: string = "string"; filteredAxis: string[] = ["string"]; filteredDirection: string[] = ["string"]; test(filteredName: `filtered${string}` & keyof this) { (this[filteredName] as string[]) = ["otherString"]; } }
- 方案2:泛型约束(兼顾多态特性和类型安全性)
给test方法增加泛型参数,约束传入的键对应的属性类型必须兼容string[]:
class Foo { axisControl: string = "string"; directionControl: string = "string"; filteredAxis: string[] = ["string"]; filteredDirection: string[] = ["string"]; test<T extends `filtered${string}` & keyof this>(filteredName: T) { this[filteredName] = ["otherString"] as this[T]; } }
这种写法下如果子类重写filtered前缀属性为不兼容string[]的类型,调用test方法时会直接抛出类型错误,避免运行时风险。
- 方案3:固定键类型约束(适合不需要子类扩展filtered前缀属性的场景)
如果业务上确定filtered前缀的属性只会在Foo类中定义,子类不会新增或修改这类属性的类型,也可以直接在参数中限定键范围为Foo的属性,回归最初的可运行写法即可。
内容的提问来源于stack exchange,提问作者Guerric P
相关产品推荐
相关产品推荐

