TypeScript类型层面实现联合类型数组无重复合法组合的约束
方案1:通用工具类型+辅助函数(推荐,可自动推断无需手动传泛型)
首先定义可复用的基础工具类型,适配任意联合类型的数组去重约束:
// 基础相等判断工具类型 type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false; // 判断元素是否存在于数组中 type Includes<T extends readonly unknown[], U> = T extends readonly [infer First, ...infer Rest] ? Equal<First, U> extends true ? true : Includes<Rest, U> : false; // 无重复数组约束类型 type UniqueArray<T, Arr extends T[] = []> = // 空数组合法 | [] // 遍历检查每个元素是否重复 | { [K in keyof Arr]: Arr[K] extends T ? Includes<Arr extends [...infer Prev, unknown] ? Prev : [], Arr[K]> extends true ? never : Arr[K] : never }
之后针对你的EventType封装校验函数,即可直接使用,后续EventType新增可选值也无需修改其他逻辑:
type EventType = "TYPE A" | "TYPE B" | "TYPE C"; function defineEventTypes<T extends EventType>(arr: UniqueArray<T>) { return arr; }
测试效果
// 合法场景,全部通过校验 const case1 = defineEventTypes([]); const case2 = defineEventTypes(["TYPE A"]); const case3 = defineEventTypes(["TYPE A", "TYPE B"]); const case4 = defineEventTypes(["TYPE B", "TYPE C", "TYPE A"]); // 非法场景,TS直接抛出类型错误 const errorCase1 = defineEventTypes(["TYPE A", "TYPE A"]); // 重复值报错 const errorCase2 = defineEventTypes(["TYPE A", "TYPE B", "TYPE B"]); // 重复值报错 const errorCase3 = defineEventTypes(["TYPE D"]); // 不在EventType范围内的值报错
方案2:直接标注类型(无需辅助函数)
如果不想用辅助函数,可以在标注类型时手动传入数组泛型参数:
// 合法 const arr1: UniqueArray<EventType, ["TYPE A", "TYPE B"]> = ["TYPE A", "TYPE B"]; // 报错:重复值 const arr2: UniqueArray<EventType, ["TYPE A", "TYPE A"]> = ["TYPE A", "TYPE A"];
额外说明
如果对数组元素顺序没有要求,优先使用Set<EventType>类型,原生就支持元素去重约束,不需要额外写工具类型,代码更简洁。
内容的提问来源于stack exchange,提问作者kimsagro
相关产品推荐
相关产品推荐

