如何让旧式类在TypeScript中生效?严格模式下无需重写类语法
让TypeScript严格模式下兼容旧式构造函数类的方案
我在大型TS迁移项目里处理过不少这类旧式函数类的问题,完全不用把所有代码都重构为class语法,几个简单的类型注解技巧就能让它们在严格模式下正常工作,还能保留原有代码结构。
核心思路:给this指定类型注解
TS在严格模式下报错'this' implicitly has type 'any',本质是因为它无法推断旧式构造函数里this的类型。我们只需要显式给this加上类型约束即可,步骤如下:
1. 先定义实例的类型接口
首先为类的实例定义一个接口,描述它的属性和方法:
interface FooClassInstance { bar: number; myMethod(): void; }
2. 给构造函数的this添加类型注解
修改构造函数,在参数列表最前面加上this: 实例接口的注解(这是TS特有的语法,不会影响JS运行):
function FooClass(this: FooClassInstance) { this.bar = 1; // 不再报'any'类型错误 }
3. 给原型方法的this也加上注解(可选但推荐)
为了让原型方法里的this也有类型提示和检查,同样给方法的this加注解:
FooClass.prototype.myMethod = function(this: FooClassInstance) { console.log(this.bar); // 这里的this会被正确推断为FooClassInstance };
进阶:让new FooClass()自动推断实例类型
上面的方法解决了this的类型错误,但如果直接用new FooClass(),TS可能还是会把实例推断为any。可以通过构造函数类型断言来解决:
// 先定义构造函数的类型:返回FooClassInstance实例 type FooClassConstructor = new () => FooClassInstance; // 把原构造函数断言为这个类型 const FooClass = function(this: FooClassInstance) { this.bar = 1; } as FooClassConstructor; // 现在使用new的时候,TS会自动推断实例类型 const foo = new FooClass(); foo.bar; // 类型是number,有语法提示 foo.myMethod(); // 正常调用
如果构造函数需要接收参数,只需要同步修改构造函数类型和接口即可:
interface FooClassInstance { bar: number; myMethod(): void; } type FooClassConstructor = new (initialBar: number) => FooClassInstance; const FooClass = function(this: FooClassInstance, initialBar: number) { this.bar = initialBar; } as FooClassConstructor; // 使用时参数类型会被检查 const foo = new FooClass(10);
为什么不用重构为class?
对于大型迁移项目,一次性把所有旧式类改成class语法成本太高,上面的方法可以零侵入保留原有代码结构,同时获得TS的类型检查能力。等后续有时间再逐步重构也完全没问题。
内容的提问来源于stack exchange,提问作者Steve Hanov
相关产品推荐
相关产品推荐

