如何告知TypeScript接口已被实现?有没有更优的接口扩展方案?
问题1解答:可以告知编译器接口已实现
你可以通过两种常用方式解决类型报错问题:
方案1:使用声明合并补全类型
在FooModel类定义后新增同名接口声明,TypeScript会自动合并类和接口的类型定义,编译器就会识别到FooModel包含FooResponse的所有属性:
interface FooResponse { test: number; } class Model { constructor(source: object) { Object.assign(this, source); Object.freeze(this); } } class FooModel extends Model implements FooResponse { constructor(source: FooResponse) { super(source); } public get squareTest() { return this.test * this.test; } } // 新增这一行声明合并即可 declare interface FooModel extends FooResponse {}
方案2:改造基类为泛型实现
直接把基类改成泛型类,通过类型断言告诉编译器返回值同时包含基类、扩展方法和原接口的属性:
class Model<T> { constructor(source: T) { Object.assign(this, source); Object.freeze(this); } } // 用交叉类型定义构造函数返回值 const FooModel = class FooModel extends Model<FooResponse> { constructor(source: FooResponse) { super(source); } public get squareTest() { return this.test * this.test; } } as new (source: FooResponse) => FooModel & FooResponse;
两种方案都不会增加额外的运行时代码,完全兼容你现有的逻辑。
问题2解答:更适合自动生成接口的扩展方案
针对OpenAPI生成的批量接口场景,有三种比手动写包装类更高效的方案:
- 方案1:纯函数扩展(零运行时开销)
不需要修改原有响应对象,直接写带类型约束的工具函数即可,无需对接口返回值做任何包装改造,适配成本最低:// 通用扩展函数,所有用到FooResponse的地方直接调用即可 export const calcSquareTest = (foo: FooResponse) => foo.test * foo.test; - 方案2:修改OpenAPI生成模板
大部分OpenAPI客户端生成工具都支持自定义模板,你可以直接修改模板配置,让生成的产物直接是类而非接口,或者在生成的接口文件中自动注入你需要的通用扩展定义,无需手动维护每个模型的包装类。 - 方案3:通用包装工厂
如果一定要用类包装的模式,可以写一个通用的工厂函数批量生成包装类,不需要为每个接口单独手写类定义:function createModelWrapper<T>() { return class extends Model<T> { constructor(source: T) { super(source); } } as new (source: T) => Model<T> & T; } // 生成FooModel只需要一行,自动继承FooResponse的所有类型 const FooModel = createModelWrapper<FooResponse>(); // 后续再给FooModel加扩展方法即可
内容的提问来源于stack exchange,提问作者SebastianStehle
相关产品推荐
相关产品推荐

