TypeScript无法推断后续添加属性的空对象类型?如何兼顾接口约束?
问题解析与解决方案
首先直接回答你的疑问:TypeScript确实无法自动推断这种动态添加的属性。原因在于TS是静态类型检查器,它在编译时会基于你提供的初始值和代码结构做类型推断——这里reduce的初始值是{},TS会把它推断为{}(空对象类型),而后续在循环里通过变量name给对象赋值,TS没办法确定name的具体值就是"objKey"(哪怕你代码里写死了数组元素),所以最终reduce的返回类型还是{},和你指定的ITest接口不匹配,自然就报错了。
接下来是几种既保证类型安全、又能消除报错的方案:
方案1:给reduce初始值显式指定类型
直接把初始空对象断言为ITest类型,让TS明确这个对象最终会符合接口约束:
interface ITest { objKey: { propA: string; propB: string; }; } const func: ITest = () => { const arr = ["objKey"]; return arr.reduce((obj, name) => { obj[name] = { propA: "str1", propB: "str2" }; return obj; }, {} as ITest); // 这里添加类型断言 };
方案2:显式标注reduce的泛型参数
通过泛型告诉reduce最终要返回的类型是ITest,初始值会自动适配这个类型:
interface ITest { objKey: { propA: string; propB: string; }; } const func: ITest = () => { const arr = ["objKey"]; // 标注reduce的泛型参数为ITest return arr.reduce<ITest>((obj, name) => { obj[name] = { propA: "str1", propB: "str2" }; return obj; }, {}); };
方案3:利用const断言让TS识别数组的具体元素
如果你的数组是固定字面量,可以用as const让TS知道数组元素是具体的字符串字面量,再通过映射类型生成对应类型,这种方式在数组多元素时更灵活:
interface ITest { objKey: { propA: string; propB: string; }; } const func: ITest = () => { const arr = ["objKey"] as const; // const断言锁定数组元素类型 return arr.reduce((obj, name) => { obj[name] = { propA: "str1", propB: "str2" }; return obj; }, {} as { [K in typeof arr[number]]: { propA: string; propB: string; } }); };
不推荐的方案:直接断言函数返回值
虽然可以直接把函数返回值断言为ITest,但这种方式会跳过TS的类型检查,后续如果修改代码导致返回值不符合接口,TS不会给出提醒,所以不建议使用:
interface ITest { objKey: { propA: string; propB: string; }; } const func: ITest = () => { const arr = ["objKey"]; return arr.reduce((obj, name) => { obj[name] = { propA: "str1", propB: "str2" }; return obj; }, {}) as unknown as ITest; };
内容的提问来源于stack exchange,提问作者user3064776
相关产品推荐
相关产品推荐

