TypeScript对象转换时能否仅通过类型实现安全键缩小?
解决方案:通过类型定义实现A到B的安全转换(无需修改核心业务逻辑)
要在不改动reduce循环核心逻辑的前提下解决类型错误,同时保留类型校验能力,可以通过映射类型和条件类型建立A与B的强类型关联,再给函数参数添加精确的类型约束,让TypeScript正确推断类型匹配关系。
完整实现代码
enum Keys { Key1 = 'key1', Key2 = 'key2', } type A = { [Keys.Key1]?: { value: string; }; [Keys.Key2]?: { value: number; }; }; // 工具类型:提取对象中value属性的类型 type ExtractValue<T> = T extends { value: infer V } ? V : never; // 基于A自动生成B的类型,保证类型强关联 type B = { [K in keyof A]?: ExtractValue<A[K]>; }; function func(obj: A): B { return Object.values(Keys).reduce( (prev, key: keyof A) => { if (key in obj) { // 非空断言:已通过key in obj确认属性存在 // 精确类型断言:匹配当前key对应的B属性类型 prev[key] = obj[key]!.value as B[typeof key]; } return prev; }, {} as B, ); }
方案说明
类型关联与校验
ExtractValue工具类型通过条件类型自动提取A中每个属性的value类型,确保B的类型完全依赖A定义。- 若手动修改B的类型与A不匹配(比如把B的
Key1设为number),TypeScript会直接抛出类型错误,满足校验需求;若A中某属性的value变为number|null,B的对应属性会自动同步为number|null|undefined。
解决类型推断问题
- 给循环中的
key标注keyof A类型,让TypeScript明确它是A的合法键,而非宽泛的string类型。 obj[key]!的非空断言是安全的:已通过key in obj判断属性存在,无需担心undefined。as B[typeof key]是精确的类型断言,针对当前key对应的B属性类型,避免了any的滥用,同时让TypeScript认可赋值操作。
- 给循环中的
额外验证:类型校验能力示例
如果修改A的类型,比如把Key2的value改为number|null:
type A = { [Keys.Key1]?: { value: string; }; [Keys.Key2]?: { value: number | null; }; };
此时B的Key2会自动变为number | null | undefined,如果手动将B的Key2定义为number,TypeScript会报错:
// 报错:Type 'number | null | undefined' is not assignable to type 'number | undefined' type B = { [Keys.Key1]?: string; [Keys.Key2]?: number; };
内容的提问来源于stack exchange,提问作者Artur Beltsov
相关产品推荐
相关产品推荐

