如何为对象键静态类型化,同时动态推导值的类型?
解决方案
要实现强制包含指定所有键,同时自动推导每个函数的具体类型,可以通过以下两种方式实现:
方法一:使用泛型辅助函数(兼容所有TS版本)
通过定义一个泛型函数,既约束对象必须包含所有指定键,又保留每个函数的具体签名:
type MyFunctionKeys = 'func1' | 'func2'; // 泛型函数:约束输入对象必须包含所有MyFunctionKeys的键,且值为函数 function createFunctions<T extends Record<MyFunctionKeys, (...args: any[]) => any>>(funcs: T): T { return funcs; } // 必须包含func1和func2,否则TS报错;每个函数的类型会被自动推导 const MyFunctions = createFunctions({ func1: (num: number) => num + 1, func2: (str: string) => str + '1', }); // 调用检查:类型正确 MyFunctions.func1(3); // 调用错误:string不能赋值给number MyFunctions.func1('3'); // 调用检查:类型正确 MyFunctions.func2('hello'); // 调用错误:number不能赋值给string MyFunctions.func2(123);
原理:泛型T会被TS自动推断为传入对象的具体类型,而T extends Record<MyFunctionKeys, ...>确保了对象必须包含所有指定键,且每个值都是函数。返回T保留了每个函数的参数和返回值类型,因此调用时能得到精准的类型校验。
方法二:使用satisfies运算符(TS 4.9+)
如果你的TypeScript版本在4.9及以上,satisfies运算符可以更简洁地实现需求:
type MyFunctionKeys = 'func1' | 'func2'; // 使用satisfies约束对象结构,但保留自动推导的具体类型 const MyFunctions = { func1: (num: number) => num + 1, func2: (str: string) => str + '1', } satisfies Record<MyFunctionKeys, (...args: any[]) => any>; // 同样能得到正确的类型校验 MyFunctions.func1(3); MyFunctions.func1('3'); // 报错 MyFunctions.func2('test'); MyFunctions.func2(456); // 报错
原理:satisfies仅检查对象是否符合指定的类型约束,但不会覆盖对象的自动推导类型。因此既保证了所有键都存在,又保留了每个函数的具体签名。
为什么直接用Record不行?
当你直接给对象标注Record<MyFunctionKeys, Function>类型时,TS会将所有函数的类型统一为宽泛的Function,丢失了具体的参数和返回值信息,导致调用时无法进行类型校验。而上述两种方式都避免了这个问题,同时满足键的完整性约束。
内容的提问来源于stack exchange,提问作者Zach Olivare
相关产品推荐
相关产品推荐

