如何确保TypeScript数组包含字符串联合类型的所有成员?
确保数组包含联合类型所有成员对应的对象条目
给定字符串联合类型:
type UnionOfStrings = "zzz" | "yyy";
以及接口定义:
interface Obj { a: string; b: UnionOfStrings; }
需要让Obj类型的数组必须包含联合类型里每一个字符串对应的条目——比如下面的示例数组缺少b: "yyy"的条目,要让TypeScript在编译阶段就检测出这个错误。
解决方案一:映射类型+元组约束
通过映射类型生成每个联合成员对应的Obj子类型,再强制数组包含所有子类型的元素:
type UnionOfStrings = "zzz" | "yyy"; interface Obj { a: string; b: UnionOfStrings; } // 生成包含所有联合成员的结构,每个成员对应专属的Obj子类型 type RequiredEntries = { [K in UnionOfStrings]: Obj & { b: K } }; // 把结构的值转为元组类型,确保数组必须覆盖所有成员 type ArrayWithAllEntries = Array<RequiredEntries[UnionOfStrings]> & { [K in keyof RequiredEntries]: RequiredEntries[K] }; // 符合要求的数组(正常通过) const validArray: ArrayWithAllEntries = [ { a: "对应zzz的内容", b: "zzz" }, { a: "对应yyy的内容", b: "yyy" }, ]; // 缺少条目时直接报错 const invalidArray: ArrayWithAllEntries = [ { a: "", b: "zzz" }, ]; // 类型错误:缺少b为"yyy"的条目
解决方案二:用satisfies做类型校验(TypeScript 4.9+)
利用satisfies运算符结合条件类型,既保证数组是Obj[],又强制覆盖所有联合成员:
type UnionOfStrings = "zzz" | "yyy"; interface Obj { a: string; b: UnionOfStrings; } // 检查数组是否覆盖了所有联合成员的b值 type HasAllEntries<T extends UnionOfStrings> = [T] extends [never] ? true : false; type CheckAllEntries<T extends Obj[]> = HasAllEntries<Exclude<UnionOfStrings, T[number]["b"]>> extends true ? T : never; // 符合要求的数组(正常通过) const validArray = [ { a: "", b: "zzz" }, { a: "", b: "yyy" }, ] satisfies CheckAllEntries<Obj[]>; // 缺少条目时报错 const invalidArray = [ { a: "", b: "zzz" }, ] satisfies CheckAllEntries<Obj[]>; // 类型不匹配
解决方案三:工具类型生成全成员元组
自定义工具类型把联合类型转为包含所有成员的元组,直接用这个元组类型约束数组:
type UnionOfStrings = "zzz" | "yyy"; interface Obj { a: string; b: UnionOfStrings; } // 工具类型:把联合类型转为包含所有成员的元组 type TupleOfUnion<T, U extends T[] = []> = Exclude<T, U[number]> extends never ? U : TupleOfUnion<T, [...U, Exclude<T, U[number]>]>; // 生成必须包含所有成员的数组类型 type RequiredArray = TupleOfUnion<{ [K in UnionOfStrings]: Obj & { b: K } }[UnionOfStrings]>; // 符合要求的数组(正常通过) const validArray: RequiredArray = [ { a: "", b: "zzz" }, { a: "", b: "yyy" }, ]; // 缺少条目时报错 const invalidArray: RequiredArray = [ { a: "", b: "zzz" }, ]; // 元组长度不足,缺少b为"yyy"的元素
这些方案的核心都是借助TypeScript的条件类型、映射类型能力,在编译期强制数组覆盖联合类型的每一个成员,避免遗漏条目。
内容的提问来源于stack exchange,提问作者Will Stone
相关产品推荐
相关产品推荐

