TypeScript如何为类动态生成的get方法实现强类型校验
链式调用add方法的强类型实现
核心通过TS映射类型动态生成getXxx格式的方法签名,再通过add方法返回交叉类型累加已添加的方法定义:
// 通用工具类型:将对象的键转换为 `getXxx` 格式的无参方法,返回对应值的类型 type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] }; class App<ObjList extends Record<string, any>> { private objects = new Map<keyof ObjList, any>(); add<T extends keyof ObjList>(name: T, value: ObjList[T]): this & Getters<Pick<ObjList, T>> { this.objects.set(name, value); (this as any)[`get${String(name)}`] = () => value; return this as this & Getters<Pick<ObjList, T>>; } }
使用示例:
const app = new App<{ Test: string, Test2: number }>() .add('Test', 'this is my test string') .add('Test2', 5); // TS可正确识别方法存在,返回值类型推导为string app.getTest(); // TS可正确识别返回值类型推导为number app.getTest2();
构造函数直接初始化的强类型实现
通过TS的声明合并特性,直接将生成的getter方法类型合并到类的实例类型中:
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] }; // 接口和类同名,自动合并类型,将getter方法注入到实例类型中 interface App<ObjList extends Record<string, any>> extends Getters<ObjList> {} class App<ObjList extends Record<string, any>> { private objects: Map<keyof ObjList, any>; constructor(initObjects: ObjList) { this.objects = new Map(Object.entries(initObjects)); Object.entries(initObjects).forEach(([key, value]) => { (this as any)[`get${key}`] = () => value; }); } }
使用示例:
// 无需手动传入泛型,TS可自动根据入参推导类型 const inst = new App({ Test: 'this is my test string', Test2: 5 }); // TS正确识别返回值类型为string inst.getTest(); // TS正确识别返回值类型为number inst.getTest2();
注意事项
- 以上实现依赖TypeScript 4.1及以上版本,用到了模板字面量类型、键重映射的特性
- 如果存在非字符串类型的键,可对Getters工具类型做扩展兼容处理
内容的提问来源于stack exchange,提问作者Adam Baranyai
相关产品推荐
相关产品推荐

