已知Record可检查对象全枚举,如何在TypeScript中检查数组穷尽性?
用TypeScript强制数组包含所有指定枚举值的元素
我们知道可以用Record类型强制对象包含所有指定的键,比如下面的例子,一旦遗漏某个Country值对应的字段,TypeScript就会直接报错:
type Country = "uk" | "france" | "india"; export const data: Record<Country, boolean> = { uk: true, france: true, // TypeScript会报错:类型"{ uk: true; france: true; }"缺少属性"india" };
现在需要实现类似的效果:当数组的每个元素都是{value: Country}类型时,要求数组必须包含所有Country枚举值对应的元素,遗漏时触发TypeScript报错。比如下面的代码,希望因为缺少{value: "india"}而提示错误:
export const data = [ {value: "uk"}, {value: "france"}, // 如何让TypeScript在此处报错提示遗漏了{value: "india"}? ];
解决方案
可以通过自定义工具类型结合as const断言和satisfies关键字来实现这个需求:
type Country = "uk" | "france" | "india"; // 自定义工具类型:验证数组是否包含所有Country枚举值对应的元素 type RequiresAllCountries<T extends {value: Country}[]> = // 先确保数组元素的value都是Country的成员 T[number]["value"] extends Country ? // 再确保Country的每个成员都能在数组的value中找到 (Country extends T[number]["value"] ? T : never) : never; // 使用as const保留字面量类型,用satisfies做类型约束 export const data = [ {value: "uk"}, {value: "france"}, {value: "india"} ] as const satisfies RequiresAllCountries<typeof data>;
原理说明
as const:强制TypeScript将数组元素的value保留为字面量类型(比如"uk"而不是string),这样才能准确校验每个元素的具体值。satisfies:用来验证数组是否符合RequiresAllCountries的约束,同时不会改变data本身的类型。RequiresAllCountries:通过双重条件判断,先确保数组里的value都属于Country,再反过来确保Country的每一个值都在数组中存在,不满足则返回never,触发TypeScript报错。
如果遗漏{value: "india"},TypeScript会抛出类似如下的错误:
Type 'readonly [{ value: "uk"; }, { value: "france"; }]' does not satisfy the expected type 'RequiresAllCountries<readonly [{ value: "uk"; }, { value: "france"; }]>'.
Type 'readonly [{ value: "uk"; }, { value: "france"; }]' is not assignable to type 'never'.
另一种实现思路
也可以借助Record的特性来间接实现,先通过Record确保所有枚举值都被覆盖,再转换为数组类型:
type Country = "uk" | "france" | "india"; // 基于Record生成包含所有枚举值的数组类型 type CountryArray = Array<{value: Country}> & { [K in keyof Record<Country, unknown>]: {value: K} }[keyof Record<Country, unknown>][]; export const data = [ {value: "uk"}, {value: "france"}, {value: "india"} ] as const satisfies CountryArray;
这个方法的核心是利用Record必须包含所有键的特性,先生成包含所有Country值的元素类型集合,再约束数组必须包含这些元素。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

