如何在TypeScript中构建带泛型的组合判别联合类型函数?
解决方案:基于联合类型的多层判别约束实现
1. 先定义基础类型映射
先把action、输入输出格式对应的类型规则统一定义,让TS能明确关联各属性的依赖关系:
// 定义支持的格式类型 type Format = 'json' | 'yaml' | 'csv'; // 映射格式对应的数据类型 type FormatData<T extends Format> = T extends 'json' ? Record<string, any> : T extends 'yaml' ? string : T extends 'csv' ? string[][] : never; // 枚举所有合法的Action参数组合(核心:用联合类型明确每个action的完整参数结构) type ActionConfig = | { action: 'convert'; input: { format: Format }; output: { format: Format }; data: FormatData<this['input']['format']>; } | { action: 'format'; input: { format: Format }; output?: never; // format动作不需要output字段 data: FormatData<this['input']['format']>; };
2. 实现call函数的类型约束与返回值推断
基于上面的联合类型,让call函数的入参和返回值做精准映射:
// 定义返回类型推断逻辑 type CallReturnType<T extends ActionConfig> = T extends { action: 'convert' } ? FormatData<T['output']['format']> : T extends { action: 'format' } ? FormatData<T['input']['format']> : never; // 实现call函数 function call<T extends ActionConfig>(params: T): CallReturnType<T> { switch (params.action) { case 'convert': // 直接复用已实现的convert函数,类型已自动关联 return convert(params.data, params.input.format, params.output.format) as CallReturnType<T>; case 'format': // 复用已实现的format函数 return format(params.data, params.input.format) as CallReturnType<T>; default: throw new Error(`Unsupported action: ${(params as any).action}`); } }
3. 扩展40+种Action的方式
新增action只需要在ActionConfig里追加新的联合成员,同步更新返回类型推断即可:
// 新增validate动作 type ActionConfig = // 原有convert、format... | { action: 'validate'; input: { format: Format; schema: Record<string, any> }; output?: never; data: FormatData<this['input']['format']>; }; // 更新返回类型推断 type CallReturnType<T extends ActionConfig> = // 原有判断逻辑... | T extends { action: 'validate' } ? boolean : never; // 在call函数中新增处理分支 case 'validate': return validate(params.data, params.input.format, params.input.schema) as CallReturnType<T>;
4. 类型校验与推断效果示例
调用时TS会自动校验参数合法性,并精准推断返回类型:
// 合法调用:convert动作,输入json→输出yaml const yamlResult = call({ action: 'convert', input: { format: 'json' }, output: { format: 'yaml' }, data: { name: 'test' } }); // yamlResult类型自动推断为string(对应yaml格式的类型) // 错误调用:convert动作的data类型与input.format不匹配 call({ action: 'convert', input: { format: 'csv' }, output: { format: 'json' }, data: { name: 'test' } // TS直接报错:类型不匹配csv要求的string[][] });
原实现出错原因
之前的问题核心是没有用完整的联合类型枚举所有合法参数组合,而是试图用分散的类型条件约束,导致TS无法关联action、input.format、output.format等多属性的依赖关系。用联合类型明确每个action的完整参数结构后,TS就能正确执行判别式类型推断。
内容的提问来源于stack exchange,提问作者Lance Pollard
相关产品推荐
相关产品推荐

