TypeScript中如何将字符串映射为匹配的模板字面量类型
解决方案
你可以通过定义通用的类型工具和转换函数实现,无需为每个属性维护对应关系,代码可复用性更高。
- 首先定义通用的模板字面量转换类型和映射类型
// 把原属性名转换为as开头的驼峰格式模板字面量类型 type AsKey<K extends string | number | symbol> = K extends string ? `as${Capitalize<K>}` : never; // 你的原映射类型,基于上面的工具类型实现更清晰 type SomeType<T> = { [P in keyof T as AsKey<P>]: number; };
- 封装通用的属性名转换函数,只需要声明一次即可适配所有类型
function getAsKey<T, K extends keyof T>(key: K): AsKey<K> { const strKey = key as string; return `as${strKey.charAt(0).toUpperCase()}${strKey.slice(1)}` as AsKey<K>; }
这里的类型断言仅封装在工具函数内部,你在业务侧使用时不需要额外做类型断言。
3. 业务侧使用示例
interface I { foo: number; bar: number; } const obj: SomeType<I> = { asFoo: 1, asBar: 2, }; // 固定字面量key的场景 const str = 'foo' as const; const value = obj[getAsKey<I>(str)]; // TS可正确识别value类型为number,属性访问完全类型安全 // 运行时动态获取string类型key的场景,可以配合类型守卫做校验 function isKeyOf<T>(key: unknown): key is keyof T { return typeof key === 'string' && ['foo', 'bar'].includes(key); // 如果不想硬写属性列表,也可以构造一个空的T实例用in判断,或者维护一个属性数组的常量即可 } const dynamicKey: string = 'bar'; // 模拟运行时获取的字符串 if (isKeyOf<I>(dynamicKey)) { const dynamicValue = obj[getAsKey<I>(dynamicKey)]; // 同样类型安全 }
原写法不生效的原因
TypeScript 不会推导运行时字符串方法的返回值为模板字面量类型,toUpperCase()、slice()这类方法的返回值类型都是通用string,拼接后的结果无法匹配到SomeType的具体字面量键类型,因此需要通过泛型函数建立输入key和输出转换后key的类型关联。
内容的提问来源于stack exchange,提问作者devbanana
相关产品推荐
相关产品推荐

