TypeScript映射对象内联合类型实现关联字段类型校验
问题原因
当前写法没有建立厂商和对应可选颜色的绑定关系,最终生成的是所有厂商、所有颜色自由组合的类型,无法实现联动校验:
CarType是两个车型配置对象组成的联合类型- 直接访问联合类型的属性时,TS会将所有成员的对应属性合并为联合类型,最终得到
{ manufacturer: "audi" | "mercedes", color: "red" | "blue" | "black" },自然不会限制厂商和颜色的匹配关系。
实现方案
要实现字段联动校验,需要生成可辨识联合类型:为每个厂商单独生成匹配其专属颜色的对象结构,再将所有合法结构组合为联合类型。
写法1:直接遍历配置对象的key生成类型
不需要额外定义冗余的中间类型,直接基于as const修饰的常量推导即可:
const cars = { "audi": { manufacturer: "audi", colors: ["red", "blue"] }, "mercedes": { manufacturer: "mercedes", colors: ["blue", "black"] } } as const type Car = { [K in keyof typeof cars]: { manufacturer: (typeof cars)[K]["manufacturer"] color: (typeof cars)[K]["colors"][number] } }[keyof typeof cars]
写法2:保留原有Mapper泛型结构
如果需要保留通用的Mapper类型,可通过条件类型触发TS对联合类型的分发特性:联合类型传入泛型时,会被拆分为单个成员逐个计算,最后合并计算结果:
const cars = { "audi": { manufacturer: "audi", colors: ["red", "blue"] }, "mercedes": { manufacturer: "mercedes", colors: ["blue", "black"] } } as const type CarType = typeof cars[keyof typeof cars] type Mapper<C extends CarType> = C extends C ? { manufacturer: C["manufacturer"] color: C["colors"][number] } : never type Car = Mapper<CarType>
校验效果
两种写法的校验效果完全一致:
// 校验通过:audi可选red/blue const car1: Car = { manufacturer: "audi", color: "red" } // 校验通过:mercedes可选blue/black const car2: Car = { manufacturer: "mercedes", color: "black" } // 校验报错:audi没有black配色 const car3: Car = { manufacturer: "audi", color: "black" // TS会直接抛出类型不匹配错误 }
内容的提问来源于stack exchange,提问作者andras
相关产品推荐
相关产品推荐

