TypeScript如何实现方法名与类型映射,动态生成接口或推导类型
实现方案
完全不需要手动定义MyInterface这类映射结构,借助TypeScript的内置工具类型能力,直接从目标类的原始类型反推出需要的[入参, 出参]映射结构,再把这套结构直接绑定到包装函数的泛型约束上,就能实现零维护的类型推导。
具体实现步骤
1. 定义通用工具类型自动生成映射结构
写一个可复用的泛型工具,遍历类的所有公开方法,自动把每个方法拆解为[入参类型, 返回值类型]的元组:
type MethodTupleMap<T> = { // 遍历类的所有公开键 [K in keyof T]: // 判断当前键对应的属性是否为函数 T[K] extends (...args: infer Args) => infer ReturnVal // 单参数场景取第一个入参,多参场景可直接使用Args作为元组 ? [Args[0], ReturnVal] // 非函数属性直接排除,不进入映射结构 : never }
这个工具生成的结构和手动写的MyInterface完全等价,而且100%和类的实际类型对齐,不会出现手动维护的偏差。比如把MyClass传进去得到的类型结构是:
// 自动推导结果,和手写MyInterface完全一致 type AutoMap = MethodTupleMap<MyClass> // AutoMap等价于 { // stringToNumber: [string, number] // numberToString: [number, string] // }
2. 改造包装函数,基于自动映射做类型推导
直接基于刚才生成的映射结构定义泛型约束,根本不需要额外声明入参、出参的独立泛型,TS会自动完成全链路类型推导:
// 提前实例化目标类,避免每次调用都重复创建实例 const myClassInstance = new MyClass() const myClassFn = <K extends keyof MethodTupleMap<MyClass>>( method: K, // 自动根据传入的method取对应入参类型做校验 value: MethodTupleMap<MyClass>[K][0] // 自动推导返回值类型 ): MethodTupleMap<MyClass>[K][1] => { // 因为类型完全对齐,不需要写as any这类类型断言 return myClassInstance[method](value) }
实际效果
之前的调用示例可以正常工作,并且获得比手写接口更严格的类型校验:
// 正常调用:类型完全匹配 const result = myClassFn("numberToString", 1) // 类型报错:method传了不存在的键 myClassFn("notExistMethod", 1) // 类型报错:numberToString的入参需要number,传了字符串 myClassFn("numberToString", "test")
扩展说明
- 如果类中的方法存在多参数入参,只需要调整
MethodTupleMap里的入参取值,把Args[0]换成全量的Args元组即可兼容,不需要大改结构 - 后续给
MyClass新增、修改方法时,这套映射结构会自动同步更新,包装函数的可选方法名、参数类型、返回值类型都会自动适配,完全不需要手动维护映射接口,从根源上避免手写接口和实际类结构不一致的问题 - 这种写法避免了独立泛型参数可能出现的类型不匹配问题,因为入参、返回值的类型完全和method参数做了强绑定,不存在手动指定泛型导致的类型错位
内容的提问来源于stack exchange,提问作者gyllenfrans
相关产品推荐
相关产品推荐

