如何在TypeScript中基于分隔字符串为嵌套对象赋值?
实现基于字符串路径的嵌套对象属性赋值函数
核心思路
要实现这个功能,核心是拆分属性路径字符串,逐层遍历嵌套对象定位到目标属性的父层级,最后完成赋值。结合TypeScript的类型系统,还能确保路径合法性与赋值的类型安全。
步骤1:实现带类型约束的通用函数
下面是一个泛型函数,既支持任意嵌套对象的属性赋值,又通过类型定义限制路径必须是对象的有效嵌套属性:
// 递归生成对象的所有合法嵌套属性路径类型 type Path<T> = T extends object ? { [K in keyof T]: `${K & string}${Path<T[K]> extends never ? '' : `.${Path<T[K]>}`}` }[keyof T] : never; function setNestedProperty<T extends object>(obj: T, path: Path<T>, value: unknown): void { const keys = path.split('.'); // 遍历到倒数第二个属性,定位目标属性的父对象 const parentObj = keys.slice(0, -1).reduce((current, key) => { // 假设所有嵌套对象已初始化,若需自动创建可添加判断逻辑 return current[key as keyof typeof current]; }, obj); // 给最终属性赋值 const finalKey = keys.pop() as keyof typeof parentObj; parentObj[finalKey] = value as typeof parentObj[typeof finalKey]; }
步骤2:结合你的User接口使用示例
基于你定义的接口,调用方式如下:
// 初始化符合User接口的对象 const user: User = { name: 'Sandeep', address: { street: 'Old Street', postcode: '12345' }, job: { industry: { name: 'Tech', sector: 'IT' }, location: 'New York', salary: 100000 } }; // 更新address.street属性 setNestedProperty(user, 'address.street', 'New Street'); console.log(user.address.street); // 输出: New Street // 更新job.industry.sector属性 setNestedProperty(user, 'job.industry.sector', 'Software'); console.log(user.job.industry.sector); // 输出: Software
步骤3:可选处理未初始化的嵌套对象
如果需要自动创建未初始化的嵌套层级(比如user.address未定义时自动生成),可以修改reduce逻辑:
function setNestedPropertyWithCreate<T extends object>(obj: T, path: Path<T>, value: unknown): void { const keys = path.split('.'); const parentObj = keys.slice(0, -1).reduce((current, key) => { // 若当前层级不存在,创建空对象适配接口类型 if (!current[key as keyof typeof current]) { current[key as keyof typeof current] = {} as typeof current[keyof typeof current]; } return current[key as keyof typeof current]; }, obj); const finalKey = keys.pop() as keyof typeof parentObj; parentObj[finalKey] = value as typeof parentObj[typeof finalKey]; }
类型安全优化
可以进一步让函数自动推导赋值的类型,避免类型不匹配:
// 自动匹配目标属性的value类型 type PathValue<T, P extends Path<T>> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? PathValue<T[K], Rest> : never : P extends keyof T ? T[P] : never; function setNestedProperty<T extends object, P extends Path<T>>( obj: T, path: P, value: PathValue<T, P> ): void { const keys = path.split('.'); const parentObj = keys.slice(0, -1).reduce((current, key) => { return current[key as keyof typeof current]; }, obj); const finalKey = keys.pop() as keyof typeof parentObj; parentObj[finalKey] = value as typeof parentObj[typeof finalKey]; }
此时如果给address.street传入数字,TypeScript会直接报错,确保类型一致性。
内容的提问来源于stack exchange,提问作者Sandeep Thomas
相关产品推荐
相关产品推荐

