TypeScript中如何无冗余实现动态更新对象嵌套值?
最优实现方案
我们可以通过统一维护运行时映射与类型推导的方式,彻底消除重复代码,同时保持函数签名不变,且无需额外类型转换。核心思路是让类型系统自动从运行时的配置映射中推导所需类型,避免手动维护重复的类型定义与校验逻辑。
完整实现代码
// 运行时维护的分类-键映射,这是唯一需要手动修改的地方 const categoryKeyMap = { categoryOne: ['a', 'b', 'c'] as const, categoryTwo: ['x', 'y', 'z'] as const } as const; // 从映射自动推导合法的分类类型 type ValidCategory = keyof typeof categoryKeyMap; // 从映射自动推导IFoo类型,无需手动维护每个分类的嵌套结构 type IFoo = { [Category in ValidCategory]: { [Key in typeof categoryKeyMap[Category][number]]: string; }; }; // 初始化对象,类型自动匹配IFoo const obj: IFoo = { categoryOne: { a: 'a_string', b: 'b_string', c: 'c_string', }, categoryTwo: { x: 'x_string', y: 'y_string', z: 'z_string', } }; // 通用校验函数:验证分类和键的合法性,并返回收窄后的类型 function getValidatedCategoryKey( category: string, key: string ): { category: ValidCategory; key: typeof categoryKeyMap[ValidCategory][number] } | null { // 校验分类是否合法 if (!(category in categoryKeyMap)) return null; const validCategory = category as ValidCategory; // 校验当前分类下的键是否合法 const validKeys = categoryKeyMap[validCategory]; if (!validKeys.includes(key as typeof validKeys[number])) return null; return { category: validCategory, key: key as typeof validKeys[number] }; } // 保持原函数签名不变的更新函数 function changeObj(category: string, key: string, value: string, obj: IFoo): void { const validated = getValidatedCategoryKey(category, key); if (!validated) return; // TypeScript可自动推断obj[validated.category][validated.key]的类型为string,无类型错误 obj[validated.category][validated.key] = value; } // 调用示例 changeObj('categoryOne', 'b', 'B_STRING', obj);
方案优势
- 极低维护成本:新增分类时,仅需在
categoryKeyMap中添加一行键数组即可,类型定义、校验逻辑、对象结构都会自动适配,无需修改其他代码。 - 类型安全无转换:通过类型推导和类型守卫,TypeScript能自动识别合法的分类与键组合,避免了
any类型或强制类型转换的使用。 - 逻辑复用:校验逻辑被封装为通用函数,无需为每个分类编写重复的类型守卫或switch分支。
- 保持原函数签名:完全满足“category和key必须为string类型”的要求,适配HTML表单输入的场景。
新增分类示例
如果需要新增categoryThree,只需修改categoryKeyMap和初始化对象:
// 更新映射 const categoryKeyMap = { categoryOne: ['a', 'b', 'c'] as const, categoryTwo: ['x', 'y', 'z'] as const, categoryThree: ['p', 'q', 'r'] as const // 新增分类 } as const; // 更新初始化对象 const obj: IFoo = { // ... 原有分类 categoryThree: { p: 'p_string', q: 'q_string', r: 'r_string', } };
此时changeObj函数无需任何修改,即可安全处理categoryThree的键更新。
内容的提问来源于stack exchange,提问作者vldmr
相关产品推荐
相关产品推荐

