TypeScript中reduce累加器推断为never类型的问题及解决方法
TypeScript reduce累加器赋值报错:类型'string | number'无法赋值给类型'never'
问题代码
const getObjectKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>; interface AB { a: string; b: number; } export function test(config: AB) { getObjectKeys(config).reduce((memo, key) => { memo[key] = config[key]; // 此处触发报错 return memo; }, {} as AB); }
报错信息
memo[key] - TS2322: 类型'string | number'无法赋值给类型'never'。类型'string'无法赋值给类型'never'。
为什么会报错?
你用{} as AB把空对象强制断言成AB类型,但空对象本身并不具备AB的任何属性,TypeScript的类型检查能识别这个逻辑矛盾。在reduce回调里,key的类型是'a' | 'b',config[key]的类型是string | number,但空对象的属性初始状态被判定为never(因为这些属性根本不存在),所以赋值时就会触发类型不匹配的错误。
用(memo as any)[key]能运行是因为any直接绕过了所有类型检查,但这会丢失TypeScript的类型安全优势,不推荐这么做。
正确的解决方法
方法1:用Partial作为累加器的中间类型
Partial<AB>表示所有属性都是可选的,刚好匹配reduce过程中逐步填充属性的场景,最后再把结果断言为完整的AB类型:
export function test(config: AB) { return getObjectKeys(config).reduce((memo, key) => { memo[key] = config[key]; return memo; }, {} as Partial<AB>) as AB; }
方法2:用Record类型初始化累加器
通过Record<keyof AB, string | number>明确累加器的键和值的类型范围,最后再断言为AB:
export function test(config: AB) { return getObjectKeys(config).reduce((memo, key) => { memo[key] = config[key]; return memo; }, {} as Record<keyof AB, string | number>) as AB; }
方法3:初始化完整的AB对象(推荐,类型最安全)
如果AB的属性有合理的默认值,直接创建一个符合AB类型的初始对象,不需要任何额外断言:
export function test(config: AB) { return getObjectKeys(config).reduce((memo, key) => { memo[key] = config[key]; return memo; }, { a: '', b: 0 }); }
内容的提问来源于stack exchange,提问作者Pasha Zherko
相关产品推荐
相关产品推荐

