TypeScript泛型工厂函数createFetcher类型推断优化需求
泛型工厂函数类型推断优化方案
问题背景
我有一个泛型工厂函数createFetcher,它接收validationStrategy并返回fetcher函数。fetcher接收schema后,返回数据的类型由validationStrategy和schema的类型共同决定。当前实现必须手动传入Key泛型参数才能正确推断返回类型(如number[]),但我希望**仅指定GenSchema(如MySchema),无需传入Key**时,fetcher仍能正确推断返回类型(而非any)。
现有实现(需手动传入Key)
const createFetcher = < Key extends keyof GenSchema, GenSchema extends Record<string, any> = Record<string, any>, >( validationStrategy: (schema: GenSchema, data: any) => ReturnType<GenSchema[Key]>, ) => { const fetcher = async <Schema extends GenSchema>( schema: Schema, ): Promise<ReturnType<Schema[Key]>> => { const data = await (await fetch('/')).json() return await validationStrategy(schema, data) } return fetcher } type MySchema<T = any> = { parse: (data: T) => T } async function main() { const schema: MySchema<number[]> = { parse: () => [1, 2, 3] } const fetcher = createFetcher<'parse', MySchema>((schema, data) => schema.parse(data)) const data = await fetcher(schema) // ^? number[] -> 类型推断正确 }
期望实现(无需传入Key)
当前直接指定GenSchema时,返回类型被推断为any,不符合预期:
type MySchema<T = any> = { parse: (data: T) => T } async function main(){ const schema: MySchema<number[]> = { parse: () => [1, 2, 3] } const fetcher = createFetcher<MySchema>((schema, data) => schema.parse(data)) const data = await fetcher(schema) // ^? any -> 不符合预期,应推断为number[] }
注:validationStrategy的类型需兼容type ValidationStrategy<Schema=any> = (schema: Schema, data: any) => any,schema可为任意对象。
解决方案
核心思路是让createFetcher的泛型直接绑定到验证策略的完整类型,利用TypeScript的工具类型和条件推断自动推导返回值类型,无需手动指定Key。
优化后的实现
type ValidationStrategy<Schema = any> = (schema: Schema, data: any) => any; const createFetcher = <T extends ValidationStrategy>(validationStrategy: T) => { // 从验证策略中提取Schema类型和动态返回类型 type BaseSchema = Parameters<T>[0]; const fetcher = async <S extends BaseSchema>( schema: S ): Promise<T extends (s: S, d: any) => infer R ? R : never> => { const data = await (await fetch('/')).json(); return validationStrategy(schema, data) as T extends (s: S, d: any) => infer R ? R : never; }; return fetcher; }; type MySchema<T = any> = { parse: (data: T) => T }; async function main() { const schema: MySchema<number[]> = { parse: () => [1, 2, 3] }; // 无需手动传入泛型参数,TypeScript自动完成推断 const fetcher = createFetcher((schema, data) => schema.parse(data)); const data = await fetcher(schema); // ^? number[] -> 类型推断正确 }
更简洁的版本
如果不需要单独定义ValidationStrategy类型,可直接通过泛型参数捕获输入输出关系:
const createFetcher = <Schema, Output>( validationStrategy: (schema: Schema, data: any) => Output ) => { return async <S extends Schema>( schema: S ): Promise<Output extends (s: S) => infer R ? R : Output> => { const data = await (await fetch('/')).json(); return validationStrategy(schema, data) as any; }; }; type MySchema<T = any> = { parse: (data: T) => T }; async function main() { const schema: MySchema<number[]> = { parse: () => [1, 2, 3] }; const fetcher = createFetcher((schema: MySchema<any>, data) => schema.parse(data)); const data = await fetcher(schema); // ^? number[] -> 类型推断正确 }
关键优化点
- 移除了
Key泛型参数,TypeScript通过验证策略函数的参数和返回值自动推断类型 - 使用
Parameters<T>工具类型提取验证策略的Schema输入类型 - 利用条件类型
infer动态推导不同Schema实例对应的返回类型 - 支持任意结构的
schema对象,符合ValidationStrategy的类型要求
内容的提问来源于stack exchange,提问作者L.Blondy
相关产品推荐
相关产品推荐

