TypeScript:如何从子函数向父工厂函数推导参数类型
基于子函数配置自动推导父工厂函数参数类型的TypeScript实现
要实现根据fetchClient调用时是否传入schema,自动推导createFetchClient中onError的参数类型,核心是让TypeScript关联起子函数的配置类型与父工厂函数的回调参数类型。以下是两种可行的实现方案:
方案一:利用条件类型与泛型函数
通过明确区分带/不带schema的配置类型,结合条件类型动态推导错误类型,让onError自动适配不同调用场景:
interface SchemaError { schemaError: any; } // 拆分配置类型,让TypeScript精准区分两种场景 type FetchClientConfig = | { schema?: never } // 无schema的配置 | { schema: any }; // 带schema的配置 // 根据配置类型推导对应的错误类型 type FetchError<T extends FetchClientConfig> = T extends { schema: any } ? Error | SchemaError : Error; interface CreateFetchClientConfig { // 泛型onError函数,根据后续调用的配置类型匹配错误参数 onError: <T extends FetchClientConfig>(error: FetchError<T>) => any; } const createFetchClient = ({ onError }: CreateFetchClientConfig) => { // 泛型fetchClient,接收具体配置类型T function fetchClient<T extends FetchClientConfig>(config: T) { if (config.schema !== undefined) { // 此处onError参数自动推断为 Error | SchemaError onError(new Error('请求失败')); onError({ schemaError: '校验失败' }); } else { // 此处onError参数自动推断为 Error onError(new Error('请求失败')); } } return fetchClient; }; // 测试:调用时不带schema,onError的error类型为Error const fetchClient1 = createFetchClient({ onError(error) { console.log(error.message); // 仅能访问Error的属性 }, }); fetchClient1({}); // 测试:调用时带schema,onError的error类型为Error | SchemaError const fetchClient2 = createFetchClient({ onError(error) { if ('schemaError' in error) { console.log(error.schemaError); // 访问SchemaError的属性 } else { console.log(error.message); // 访问Error的属性 } }, }); fetchClient2({ schema: {} });
关键说明:
- 拆分配置类型:将
FetchClientConfig拆分为两个明确分支,避免可选属性导致的类型模糊。 - 条件类型推导错误:
FetchError<T>根据配置类型自动返回对应的错误联合类型。 - 泛型onError函数:让
onError能根据fetchClient的调用参数动态匹配错误类型,无需手动指定泛型。
方案二:利用函数重载
通过给返回的fetchClient定义重载签名,明确不同配置对应的错误类型:
interface SchemaError { schemaError: any; } interface CreateFetchClientConfig<E> { onError: (error: E) => any; } // 定义fetchClient的两个重载签名,对应不同配置场景 type FetchClient = { (config: { schema?: never }): void; (config: { schema: any }): void; }; const createFetchClient = <E>({ onError }: CreateFetchClientConfig<E>) => { const fetchClient: FetchClient = (config: { schema?: any }) => { if (config.schema !== undefined) { onError(new Error('请求失败') as Error | SchemaError); onError({ schemaError: '校验失败' } as SchemaError); } else { onError(new Error('请求失败') as Error); } }; return fetchClient; }; // 测试:无schema调用,onError的error为Error const fetchClient1 = createFetchClient({ onError(error) { console.log(error.message); }, }); fetchClient1({}); // 测试:带schema调用,onError的error为Error | SchemaError const fetchClient2 = createFetchClient({ onError(error) { if ('schemaError' in error) { console.log(error.schemaError); } else { console.log(error.message); } }, }); fetchClient2({ schema: {} });
关键说明:
- 重载签名:通过给
FetchClient定义两个重载,明确告知TypeScript不同配置对应的函数行为。 - 类型断言:在函数内部调用
onError时,需要用类型断言明确错误类型,配合重载实现类型推导。
内容的提问来源于stack exchange,提问作者L.Blondy
相关产品推荐
相关产品推荐

