TypeScript实现可插拔函数时如何推断新增方法的类型?
实现可插拔函数的类型推断方案
你当前写法无法正确推断新增方法类型的核心原因是:TypeScript的断言函数只能对**函数自身的参数或this**做类型断言,无法直接修改闭包捕获变量的类型。我们可以通过调整断言目标为this,并提取精确的方法类型来解决这个问题。
完整实现代码
export function register<T>(o: T) { // 泛型K指定属性名,V从value中提取精确方法类型 return <K extends PropertyKey, V extends Function>( this: T, p: K, attributes: PropertyDescriptor & { value: V } & ThisType<unknown>, ): asserts this is T & Record<K, V> => { Object.defineProperty(this, p, attributes); }; } // 声明mylib的基础类型,包含register方法的类型定义 type Mylib = (() => void) & { register?: ReturnType<typeof register<() => void>>; }; export const mylib = (() => {}) as Mylib; // 挂载register方法 mylib.register = register(mylib); // 注册teste方法,TypeScript将自动推断其类型 mylib.register('teste', { writable: false, value(a: number, b: number) { return a + b; }, }); console.info("a:", mylib.teste(1, 1)); // 类型推断正常,输出2 console.info("a:", mylib.teste('1', '1')); // 触发类型错误,符合预期
关键调整说明
断言
this类型:
调用mylib.register时,this会绑定到mylib本身。通过asserts this is T & Record<K, V>,我们直接扩展了this(即mylib)的类型,让TypeScript能识别新增的属性。提取精确方法类型:
新增泛型V,从attributes.value中提取具体的函数类型,替代原来宽泛的PropertyDescriptorValue,确保类型推断的精准度。提前声明类型:
通过type Mylib提前定义mylib的结构,确保register方法的类型被正确识别,避免TypeScript将其推断为any。
简化写法(无需提前声明类型)
如果不想提前定义类型,也可以在赋值register时用类型断言:
export const mylib = () => {}; // 赋值时指定register的类型 mylib.register = register(mylib) as typeof mylib['register'];
内容的提问来源于stack exchange,提问作者Adrian Miranda
相关产品推荐
相关产品推荐

