TypeScript 4.7如何实现仅窄化类型不扩展类型的转换函数
TypeScript 联合类型转换函数的精准类型推导方案
实现思路
要实现入参为ALL联合类型子类型时返回值自动窄化为对应转换结果,核心是通过类型映射表显式绑定输入标识和输出类型的对应关系,配合泛型索引推导替代默认的全量联合返回。
完整实现代码
首先补全基础依赖类型,定义转换规则映射:
// 基础业务类型声明 interface Animal { id: string; name: string; } interface ZooKeeper { id: string; name: string; } interface Visitor { id: string; } interface TaggedAnimal extends Animal { tag: string; } interface Keeper { id: string; } // 通用Base类型与全量响应联合 type Base<NAME extends string, T> = { name: NAME; value: T; } type ALL = Base<'Animal', Animal> | Base<'ZooKeeper', ZooKeeper> | Base<'Visitor', Visitor>; // 转换规则映射表:key为输入的name字面量,value为对应转换后的输出类型 type TransformMap = { Animal: Base<'TaggedAnimal', TaggedAnimal>; ZooKeeper: Base<'Keeper', Keeper>; Visitor: Base<'Visitor', Visitor>; };
实现带精准类型推导的转换函数:
const transformer = <IN extends ALL>(value: IN): TransformMap[IN['name']] => { if (value.name === 'Animal') { return { name: 'TaggedAnimal', value: { ...value.value, tag: 'mytag' } } as TransformMap[IN['name']]; } if (value.name === 'ZooKeeper') { return { name: 'Keeper', value: { id: value.value.id } } as TransformMap[IN['name']]; } // 其余类型原样返回 return value as TransformMap[IN['name']]; };
效果验证
const getAnimal = (): Base<'Animal', Animal> => { return { name: 'Animal', value: { id: '123', name: 'Lion' } }; }; const getZooKeeper = (): Base<'ZooKeeper', ZooKeeper> => { return { name: 'ZooKeeper', value: { id: '456', name: 'Tom' } }; }; const getVisitor = (): Base<'Visitor', Visitor> => { return { name: 'Visitor', value: { id: '789' } }; }; // 单类型传入时返回类型自动窄化,无多余联合分支 const animal = getAnimal(); const taggedAnimal = transformer(animal); // 类型为 Base<'TaggedAnimal', TaggedAnimal> ✅ const keeper = getZooKeeper(); const taggedKeeper = transformer(keeper); // 类型为 Base<'Keeper', Keeper> ✅ const visitor = getVisitor(); const sameVisitor = transformer(visitor); // 类型为 Base<'Visitor', Visitor> ✅ // 传入全量联合类型时,自动推导为所有合法输出的联合 const randomResp: ALL = Math.random() > 0.5 ? animal : Math.random() > 0.5 ? keeper : visitor; const transformedAll = transformer(randomResp); // 类型为 Base<'TaggedAnimal', TaggedAnimal> | Base<'Keeper', Keeper> | Base<'Visitor', Visitor> ✅
说明
- 该方案完全兼容TypeScript 4.7版本,无需升级TS版本或引入额外依赖
- 函数内部的类型断言属于TS控制流分析的已知限制:TS无法在泛型函数内部自动关联分支返回值与索引访问类型的对应关系,该断言仅作用于函数内部,不会破坏外部调用的类型安全
- 后续新增转换规则时,只需要在
ALL联合类型、TransformMap映射表和函数分支逻辑中同步添加即可,类型推导会自动适配
内容的提问来源于stack exchange,提问作者Josejulio
相关产品推荐
相关产品推荐

