使用箭头函数在reduce中返回累加器的TypeScript类型错误问题
push&&acc出现类型错误的原因及解决逻辑 问题场景
先看这段可正常运行但会触发TypeScript类型错误的代码:
const names = { bob: 20, john: 25, michael: 30 }; const result = Object.entries(names).reduce( (acc, [name, age]) => acc.push(`${name} is ${age}`) && acc, [] as string[] );
TypeScript抛出的错误为:
Type 'number' is not assignable to type 'string[]'
错误原因
这个number类型来自Array.prototype.push()的返回值——push方法执行后会返回数组的新长度,类型为number。
在reduce的回调函数中,TypeScript要求回调的返回值类型必须和累加器acc的类型(这里是string[])完全一致。而acc.push(...) && acc这个表达式中,逻辑与&&会先执行左侧的push得到number类型值,虽然运行时因为数组长度永远大于0(属于truthy值),最终会返回右侧的acc(string[]类型),但TypeScript的静态类型检查无法预知push返回的具体数值,它会将整个表达式的返回值类型推断为number(左侧操作的返回类型),这就和reduce要求的string[]类型不匹配,因此抛出错误。
三种写法的解决逻辑
写法一
const result = Object.entries(names).reduce( (acc, [name, age]) => (acc.push(`${name} is ${age}`) as 1) && acc, [] as string[] );
通过类型断言as 1,把push返回的number类型强制指定为具体的truthy值1,TypeScript会判断左侧操作是truthy,因此整个&&表达式的返回类型会被推断为右侧的acc类型(string[]),匹配reduce的要求。
写法二
const result = Object.entries(names).reduce( (acc, [name, age]) => (acc.push(`${name} is ${age}`) as {}) && acc, [] as string[] );
将push的返回值断言为{}(一个truthy的非number类型),同样让TypeScript认定左侧操作是truthy,从而推断整个表达式返回右侧的acc类型,消除类型不匹配的错误。
写法三
const result = Object.entries(names).reduce( (acc, [name, age]) => { acc.push(`${name} is ${age}`) return acc; }, [] as string[] );
这是最规范的写法:直接在回调函数体内执行push操作,然后明确返回acc,让TypeScript清晰地判断回调返回值就是string[]类型,完全符合reduce的类型约束,从根源上避免了类型推断的歧义。
内容的提问来源于stack exchange,提问作者Mike K

