如何根据传入对象的键扩展对象并实现TypeScript类型推导?
实现动态生成set方法的TypeScript类型化
要解决这个问题,核心是通过TypeScript的模板字面量类型和映射类型,精确描述返回对象的结构,让TypeScript能识别动态生成的setXXX方法。
步骤1:实现运行时的首字母大写函数
首先补全你代码中缺失的ucFirst函数:
function ucFirst(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); }
步骤2:定义类型工具
通过类型编程生成对应setXXX方法的类型:
// 将键名首字母大写的类型工具 type CapitalizeKey<K extends string> = Capitalize<K>; // 生成所有set方法的类型映射 type SetMethods<T extends Record<string, any>> = { [K in keyof T as `set${CapitalizeKey<K>}`]: (value: T[K]) => void; };
步骤3:改造getData函数
修改函数的返回类型,将原对象类型与生成的set方法类型合并,并通过类型断言让TypeScript识别动态添加的属性:
const getData = <T extends Record<string, any>>(initState: T): T & SetMethods<T> => { // 初始化时复制原状态,同时断言为目标类型 const temp = { ...initState } as T & SetMethods<T>; for (const [key, _] of Object.entries(initState)) { // 动态添加set方法,并指定参数类型为对应属性的类型 temp[`set${ucFirst(key)}` as keyof SetMethods<T>] = (value: T[typeof key]) => { // 这里可以实现实际的状态更新逻辑,例如: temp[key as keyof T] = value; } as SetMethods<T>[keyof SetMethods<T>]; } return temp; };
测试效果
现在调用getData后,TypeScript会正确识别所有属性和set方法:
const a = getData({ test: 'demo', count: 123 }); // 原属性有类型提示 a.test; // 类型:string a.count; // 类型:number // set方法有正确的参数类型提示 a.setTest('new demo'); // 参数必须是string类型 a.setCount(456); // 参数必须是number类型
原代码问题分析
你之前的代码返回的是Record<string, any>,这是一个宽泛的类型,TypeScript无法推断出具体的键和方法信息。通过上述类型工具,我们将返回类型精确为T & SetMethods<T>,既保留了原对象的所有属性类型,又添加了动态生成的set方法类型。
内容的提问来源于stack exchange,提问作者TheWuif
相关产品推荐
相关产品推荐

