如何基于Record键值收窄TypeScript可辨识联合类型?
如何让Record类型根据可辨识联合的type键自动推断对应值的类型?
我有一个包含type可辨识属性的联合类型,现在要声明一个Record类型,键是联合类型中type属性的值。怎么声明Record的第二个泛型参数,让记录里的值能根据对应键自动推断出正确的类型?
interface Dog { type: 'dog'; breed: string; } interface Vehicle { type: 'vehicle'; max_speed: number; }; type Thing = Dog | Vehicle; const printMap: Record<Thing['type'], (thing: Thing) => string> = { 'dog': x => `Dog ${x.breed}`, // ^^^^^ 类型“Thing”上不存在属性“breed”。类型“Vehicle”上不存在属性“breed”。 // 怎么让TypeScript知道因为键是'dog',所以x是Dog类型? 'vehicle': x => `Vehicle max speed ${x.max_speed}` // ^^^^^^^^^ 类型“Thing”上不存在属性“max_speed”。类型“Dog”上不存在属性“max_speed”。 // 怎么让TypeScript知道因为键是'vehicle',所以x是Vehicle类型? }
解决方案:用映射类型替代Record
Record的第二个泛型参数是统一的类型,没办法根据不同的键做差异化推断。你需要用映射类型来为每个type键关联对应的具体类型:
首先定义一个匹配可辨识联合的映射类型:
type ThingMap = { // 遍历Thing的所有type值作为键 [T in Thing['type']]: // 从Thing中提取type等于当前T的具体类型,作为函数参数 (thing: Extract<Thing, { type: T }>) => string; };
然后把printMap的类型改成ThingMap:
const printMap: ThingMap = { 'dog': x => `Dog ${x.breed}`, // x自动推断为Dog类型,不再报错 'vehicle': x => `Vehicle max speed ${x.max_speed}` // x自动推断为Vehicle类型,不再报错 };
通用化工具类型(可选)
如果需要复用这个逻辑,可以把它封装成通用工具类型:
// T是带type可辨识属性的联合类型,V是函数返回值类型(默认string) type DiscriminatedRecord<T extends { type: string }, V = string> = { [K in T['type']]: (item: Extract<T, { type: K }>) => V; }; // 使用时直接传入你的联合类型即可 const printMap: DiscriminatedRecord<Thing> = { 'dog': x => `Dog ${x.breed}`, 'vehicle': x => `Vehicle max speed ${x.max_speed}` };
内容的提问来源于stack exchange,提问作者Jeremy Danyow
相关产品推荐
相关产品推荐

