TypeScript类型安全实现Record转Map,如何避免as类型断言
优化方案
你需要用到as断言的核心原因是:TypeScript 内置的Object.entries类型定义返回的键默认是string类型,无法自动匹配你定义的泛型MyString,同时值的类型推断也会和预期的[number, number][]不匹配。
你可以选择以下任意一种方案优化,避免业务逻辑里出现零散的类型断言:
方案1:外层统一断言(改动最小)
将多处分散的断言合并为外层的一次统一断言,逻辑更清晰也更易维护:
type MyReturn<Str> = Map<Str, Map<number, number>>; export const mapRecordToMap = <MyString extends string>(data: Record<MyString, [number, number][]>) : MyReturn<MyString> => { const myReturn = new Map<MyString, Map<number, number>>(); // 仅在外层做一次类型断言,内部逻辑无需额外断言 (Object.entries(data) as [MyString, [number, number][]][]).forEach(([key, value]) => { myReturn.set(key, new Map(value)); }); return myReturn; };
方案2:封装通用类型安全工具函数(适合多场景复用)
如果你项目里有多处需要遍历对象键值对的需求,可以封装一个通用的objectEntries工具函数,后续所有调用场景都不需要额外写断言:
// 全局通用工具函数,仅需定义一次即可全局复用 function objectEntries<T extends Record<string, unknown>>(obj: T): [keyof T, T[keyof T]][] { return Object.entries(obj) as [keyof T, T[keyof T]][]; } type MyReturn<Str> = Map<Str, Map<number, number>>; export const mapRecordToMap = <MyString extends string>(data: Record<MyString, [number, number][]>) : MyReturn<MyString> => { const myReturn = new Map<MyString, Map<number, number>>(); objectEntries(data).forEach(([key, value]) => { myReturn.set(key, new Map(value)); }); return myReturn; };
这种方案本质是把通用的断言逻辑封装到工具函数内部,对外暴露完全类型安全的调用接口,符合TS类型设计规范,因为我们可以保证输入的Record类型的键确实是我们定义的泛型类型,这个断言是完全安全的。
内容的提问来源于stack exchange,提问作者Horyzont
相关产品推荐
相关产品推荐

