You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何确保TypeScript接口包含枚举的所有值作为键?

解决TypeScript枚举全键映射的强制约束问题

假设我们有如下枚举:

enum Cars {
  Volvo = 'Volvo',
  Hyundai = 'Hyundai',
  Kia = 'Kia',
  Tesla = 'Tesla'
}

需求是定义一个类型/接口,必须包含所有枚举值作为键,每个键的对应类型可以不同,新增枚举值时如果没补全映射就报错。之前尝试继承Record<Cars, Factory>无法触发缺失属性的错误,下面给出两种可行方案:

方案一:使用satisfies关键字(TypeScript 4.9+ 推荐)

先定义基础的映射类型,然后用satisfies关键字约束对象必须匹配Record<Cars, Factory>,同时保留每个键的具体类型:

// 先定义各个工厂类型示例
type SwedishFactoryType = { location: 'Sweden' };
type KoreanFactoryType = { location: 'Korea' };
type AmericanFactoryType = { location: 'USA' };
type Factory = SwedishFactoryType | KoreanFactoryType | AmericanFactoryType;

// 定义映射对象并约束
const carToFactory = {
  [Cars.Volvo]: { location: 'Sweden' } as SwedishFactoryType,
  [Cars.Hyundai]: { location: 'Korea' } as KoreanFactoryType,
  [Cars.Kia]: { location: 'Korea' } as KoreanFactoryType,
  // 注释掉Tesla的话会直接报错:属性 "Tesla" 缺失
  [Cars.Tesla]: { location: 'USA' } as AmericanFactoryType
} satisfies Record<Cars, Factory>;

// 提取类型供CarPassport使用
type CarToFactory = typeof carToFactory;

这样后续新增Cars枚举值时,只要没在carToFactory里补全对应键,TypeScript就会直接报错。同时CarToFactory类型会保留每个键的具体工厂类型,而非统一的Factory联合类型。

方案二:利用类型约束强制完全匹配

如果项目使用的TypeScript版本低于4.9,可以通过辅助类型检查是否存在缺失键:

type SwedishFactoryType = { location: 'Sweden' };
type KoreanFactoryType = { location: 'Korea' };
type AmericanFactoryType = { location: 'USA' };
type Factory = SwedishFactoryType | KoreanFactoryType | AmericanFactoryType;

// 定义映射接口
interface CarToFactory {
  [Cars.Volvo]: SwedishFactoryType;
  [Cars.Hyundai]: KoreanFactoryType;
  [Cars.Kia]: KoreanFactoryType;
  // 缺失Tesla的话,下面的类型检查会报错
  [Cars.Tesla]: AmericanFactoryType;
}

// 辅助类型:检查CarToFactory是否包含所有Cars键,缺失则返回never触发错误
type EnsureAllCarsMapped<T extends Record<Cars, Factory>> = T;
// 触发检查,缺失键时这里会报错
type CheckCarMapping = EnsureAllCarsMapped<CarToFactory>;

当CarToFactory缺失某个枚举键时,EnsureAllCarsMapped<CarToFactory>会因为CarToFactory不满足Record<Cars, Factory>而报错,强制开发者补全映射。

配合泛型接口CarPassport使用

两种方案生成的CarToFactory类型都可以直接用于你的泛型接口:

interface CarPassport<TCar extends Cars> {
  company: TCar;
  manufacturer: CarToFactory[TCar];
  year: number;
}

// 示例使用
const volvoPassport: CarPassport<Cars.Volvo> = {
  company: Cars.Volvo,
  manufacturer: { location: 'Sweden' },
  year: 2024
};

这样manufacturer的类型会根据TCar自动推导为对应的工厂类型,类型安全得到保障。

内容的提问来源于stack exchange,提问作者Artem Yankin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 07:40:17