TypeScript中如何确保多个联合类型无交集、成员唯一?
确保字符串联合类型无交集的TypeScript解决方案
我有几个本质为枚举的字符串联合类型,分别指代不同事物,同时还有一个不区分类型的查找表。如果这些类型存在交集,会引发逻辑错误,示例代码如下:
type SandwichKind = "ham" | "eggSalad" | "meatball" type SoupKind = "mushroom" | "broccoli" | "potato" class MenuItem{} class Soup extends MenuItem { soupKind : SoupKind constructor(kind: SoupKind){ super() this.soupKind = kind } } let caloriesByMenuItem : Record<SandwichKind | SoupKind, number> = { ham : 100, eggSalad: 150, meatball: 400, mushroom: 100, broccoli: 125, potato: 75 }
这段代码原本运行正常,但如果给SoupKind添加"meatball"值,就会和SandwichKind产生交集。此时查找表caloriesByMenuItem中已有的"meatball"条目容易被忽略复用,导致肉丸汤和肉丸三明治共享相同卡路里值,引发错误。需要确保SoupKind与SandwichKind无交集,一旦存在重叠就触发编译错误。
解决方法
1. 用类型约束强制检查无交集
定义一个工具类型,通过条件类型判断两个联合类型是否存在交集,若存在则返回never,触发编译错误:
// 工具类型:检测两个类型是否有交集,有交集返回never,无交集返回true type EnsureNoIntersection<T, U> = Extract<T, U> extends never ? true : never; // 强制执行检查,若SandwichKind和SoupKind有交集,此处会报错 type _EnforceNoOverlap = EnsureNoIntersection<SandwichKind, SoupKind>;
当两个类型存在重叠时,Extract<T, U>会提取出交集部分,此时条件类型返回never,赋值给_EnforceNoOverlap会触发TypeScript的编译错误,提醒开发者修复重叠问题。
2. 给类型值加前缀从根源避免重叠
直接给不同类型的字符串值添加专属前缀,从命名上杜绝交集可能,后续维护也更清晰:
type SandwichKind = "sandwich-ham" | "sandwich-eggSalad" | "sandwich-meatball"; type SoupKind = "soup-mushroom" | "soup-broccoli" | "soup-potato";
这种方法简单直观,完全避免了类型值重叠的可能,适合大多数场景。
3. 用枚举替代字符串联合类型
如果场景允许,用枚举来定义这些类型,通过给枚举值加前缀确保唯一性:
enum SandwichKind { Ham = "sandwich-ham", EggSalad = "sandwich-eggSalad", Meatball = "sandwich-meatball" } enum SoupKind { Mushroom = "soup-mushroom", Broccoli = "soup-broccoli", Potato = "soup-potato" }
枚举类型在TypeScript中有更强的类型约束,即使枚举键不小心重复,只要值不重叠,类型系统也会严格区分两者,同时也提升了代码的可读性和可维护性。
内容的提问来源于stack exchange,提问作者Sam Spade
相关产品推荐
相关产品推荐

