如何在TypeScript中实现类型安全的双向映射函数?
类型安全的双向映射函数实现(TypeScript)
问题背景
需要实现两组词汇的双向映射(例如 GB ↔ United_Kingdom、FR ↔ France),要求仅定义一次映射关系,就能生成两个方向的类型安全转换函数,确保输入输出的类型能被TypeScript精确推导(比如输入"a"时返回类型"A",而非"A"|"B")。
原JavaScript版本可实现功能,但无类型保障:
function createMappers(map) { const invertedMap = Object.entries(map).reduce( (inverted, [key, value]) => ({ ...inverted, [value]: key }), {}, ); const leftToRight = (from) => map[from]; const rightToLeft = (to) => invertedMap[to]; return [leftToRight, rightToLeft]; } const map = { a: "A", b: "B" }; const [toRight, toLeft] = createMappers(map); const one = toRight("a"); // 期望类型为 "A",但实际无类型约束 const two = toLeft("B"); // 期望类型为 "b",但实际无类型约束
TypeScript解决方案
通过泛型、类型断言和条件类型,我们可以实现完全类型安全的双向映射:
function createMappers<T extends Readonly<Record<string, string>>>(map: T) { // 构建反转映射并指定类型 const invertedMap = Object.entries(map).reduce( (acc, [key, value]) => ({ ...acc, [value]: key }), {} as { [V in T[keyof T]]: keyof T } ); // 左→右转换:输入为T的键,输出对应精确值类型 const toRight = <K extends keyof T>(key: K): T[K] => map[key]; // 右→左转换:输入为T的值,输出对应精确键类型 const toLeft = <V extends T[keyof T]>(value: V): Extract<keyof T, { [K in keyof T]: T[K] extends V ? K : never }[keyof T]> => invertedMap[value]; // 使用as const确保返回的元组类型被固定 return [toRight, toLeft] as const; } // 定义映射时用as const断言,保留字面量类型 const countryMap = { GB: "United_Kingdom", FR: "France", a: "A", b: "B" } as const; const [codeToName, nameToCode] = createMappers(countryMap); // 类型推导完全精确 const ukName = codeToName("GB"); // 类型为 "United_Kingdom" const frCode = nameToCode("France"); // 类型为 "FR" const valA = codeToName("a"); // 类型为 "A" const keyB = nameToCode("B"); // 类型为 "b" // 错误输入会被TypeScript即时报错 // codeToName("US"); // 类型错误:"US" 不在 keyof typeof countryMap 中 // nameToCode("Germany"); // 类型错误:"Germany" 不在 typeof countryMap[keyof typeof countryMap] 中
核心要点
as const断言映射对象:确保TypeScript将映射的键和值视为只读字面量类型,而非宽泛的string,为精确类型推导提供基础。- 泛型约束
T:限制输入为只读的字符串键值对对象,避免非法输入。 - 反转映射的类型定义:通过
{ [V in T[keyof T]]: keyof T }明确反转映射的键值类型关系。 - 精确类型推导:
toRight函数利用泛型K extends keyof T,让输入键对应的输出值类型精确到具体字面量。toLeft函数通过条件类型和Extract工具类型,根据输入的值反向推导出对应的键类型,实现双向的精确映射。
内容的提问来源于stack exchange,提问作者Tamlyn
相关产品推荐
相关产品推荐

