TypeScript:如何让函数集合中函数的参数类型可被正确推断?
当然可以做到!问题的核心在于你原来的FunctionCollection索引签名强制所有函数共享同一个参数类型(比如any),这会让TypeScript把具体函数的参数类型“抹平”成这个统一类型,导致ArgType无法推断出具体的string。要解决这个问题,我们需要让FunctionCollection允许每个函数保留自己的参数类型,而不是用统一的类型约束。
方案1:使用泛型映射类型定义FunctionCollection
我们可以把FunctionCollection定义为一个泛型类型,让每个键对应的函数参数类型由泛型参数指定:
// 保留原来的ArgType定义 type ArgType<F> = F extends (a: infer A) => any ? A : any; // 定义泛版FunctionCollection,每个函数的参数类型对应T中对应键的类型 type FunctionCollection<T> = { [K in keyof T]: (s: T[K]) => any; }; // 使用时指定泛型参数,或者让TypeScript自动推断 const fnCol: FunctionCollection<{ someFn: string }> = { someFn: (s: string) => 500 }; // 现在可以正确推断出string类型 type InferredType = ArgType<typeof fnCol["someFn"]>; // 类型为string
方案2:用辅助函数自动推断类型
如果你不想手动指定泛型参数,可以创建一个辅助函数让TypeScript自动推断每个函数的参数类型:
type ArgType<F> = F extends (a: infer A) => any ? A : any; // 辅助函数,用于推断集合中每个函数的具体类型 function createFunctionCollection<T extends Record<string, (s: any) => any>>(collection: T): T { return collection; } // 调用函数时,TypeScript会自动推断每个函数的参数类型 const fnCol = createFunctionCollection({ someFn: (s: string) => 500, anotherFn: (n: number) => "hello" }); // 验证推断结果: type StringType = ArgType<typeof fnCol["someFn"]>; // string type NumberType = ArgType<typeof fnCol["anotherFn"]>; // number
为什么原来的写法不行?
原来的FunctionCollection用了{ [key: string]: (s: ???) => any }这种索引签名,意味着所有属性的函数必须共享同一个参数类型。如果你填any,TypeScript会把someFn的参数类型从string拓宽到any;如果填其他固定类型,又无法兼容不同参数类型的函数。而上面的两种方案都避免了这种“统一类型约束”,让每个函数能保留自己的具体参数类型,从而让ArgType可以正确推断。
内容的提问来源于stack exchange,提问作者Gerrit Begher
相关产品推荐
相关产品推荐

