如何将TypeScript联合类型映射为具备类型安全的JavaScript Map对象?
实现TypeScript中Modifier名称与对应类型的严格映射
要解决这个键值类型严格匹配的问题,核心是让TypeScript明确每个字符串名称对应的具体类型,而不是只依赖宽泛的联合类型。下面是完整的实现方案:
1. 明确子类型与名称-类型映射
首先我们需要把各个Modifier子类型单独定义(假设你还没明确这些定义,这里补全示例),然后创建一个核心映射类型,把每个名称和对应的类型一一绑定:
// 定义各个Modifier子类型 type RangeModifier = { from: Date; to: Date }; type BeforeModifier = { before: Date }; type AfterModifier = { after: Date }; type BeforeAfterModifier = { before: Date; after: Date }; type DaysOfWeekModifier = { days: number[] }; type FunctionModifier = (date: Date) => boolean; // 关键:名称到对应类型的映射,这是类型安全的基础 type ModifierTypeMap = { 'undefined': undefined; 'Date': Date; 'RangeModifier': RangeModifier; 'BeforeModifier': BeforeModifier; 'AfterModifier': AfterModifier; 'BeforeAfterModifier': BeforeAfterModifier; 'DaysOfWeekModifier': DaysOfWeekModifier; 'FunctionModifier': FunctionModifier; };
2. 自动推导Modifier联合类型和名称类型
基于上面的映射类型,我们可以自动推导之前定义的Modifier和ModifierNames,避免手动维护重复内容:
// 从映射类型自动生成Modifier联合类型 type Modifier = ModifierTypeMap[keyof ModifierTypeMap]; // 从映射类型的键自动生成ModifierNames类型 type ModifierNames = keyof ModifierTypeMap; // 如果需要名称数组常量(TypeScript 5.1+支持) const MODIFIER_NAMES = Object.keys(ModifierTypeMap) as const satisfies readonly ModifierNames[];
3. 创建类型安全的Map
普通的Map<ModifierNames, Modifier>无法约束键值对应关系,因为Modifier是联合类型,TypeScript会允许任何Modifier值和任意键搭配。我们需要重写set和get方法的类型,让它们严格对应映射关系:
// 定义类型安全的Map类型:每个键K对应的值必须是ModifierTypeMap[K] type TypeSafeModifierMap = { set<K extends ModifierNames>(key: K, value: ModifierTypeMap[K]): void; get<K extends ModifierNames>(key: K): ModifierTypeMap[K] | undefined; } & Omit<Map<ModifierNames, Modifier>, 'set' | 'get'>; // 创建实例并断言类型 const modifierMap: TypeSafeModifierMap = new Map<ModifierNames, Modifier>() as TypeSafeModifierMap;
4. 测试类型安全
现在我们可以验证键值匹配的约束是否生效:
// 测试用例 const rangeModifier: RangeModifier = { from: new Date(), to: new Date() }; const beforeModifier: BeforeModifier = { before: new Date() }; // ✅ 合法操作:键与值类型完全匹配 modifierMap.set('RangeModifier', rangeModifier); modifierMap.set('BeforeModifier', beforeModifier); modifierMap.set('Date', new Date()); modifierMap.set('undefined', undefined); // ❌ 非法操作:键值类型不匹配,TypeScript会直接报错 modifierMap.set('BeforeModifier', rangeModifier); modifierMap.set('RangeModifier', beforeModifier);
为什么这个方案有效?
ModifierTypeMap是整个类型安全的核心,它消除了联合类型的模糊性,让TypeScript明确每个名称对应的具体类型TypeSafeModifierMap通过泛型的set/get方法,强制要求传入的值必须和键对应的类型一致,而不是接受任意的Modifier类型- 用
& Omit<Map<...>, 'set' | 'get'>保留了原生Map的其他方法(比如has、delete),只重写需要类型约束的方法
内容的提问来源于stack exchange,提问作者Realm Of Code
相关产品推荐
相关产品推荐

