TS2322报错:string类型无法赋值给never类型问题排查
报错根本原因
这个报错来自TypeScript对联合类型索引访问的安全检查逻辑限制:
- 你的
FormsKey是'login' | 'forgot'的联合类型,映射类型FormsMap的两个属性值分别是专属的字符串字面量类型`forms.login`和`forms.forgot`,这两个类型没有任何重叠的可能值。 - 在
reduce的回调函数里,key的类型是整个联合FormsKey,TS无法确定代码运行时key到底是'login'还是'forgot'。为了保证不会出现给result.login赋`forms.forgot`这种错误,TS会要求赋值给result[key]的值必须同时满足所有可能属性的类型要求,也就是值的类型得是`forms.login` & `forms.forgot`。但这两个字符串字面量没有公共交集,交叉后得到的类型就是never——代表不存在这样的值,所以你不管赋什么字符串类型的值都会报类型不匹配。 - 去掉
forms.前缀就不报错的原因也很简单:当你直接写result[key] = key时,TS的类型流分析能识别到赋值的key和索引用的key是同一个值,可以自动证明类型匹配;但加了模板字符串前缀后,TS的类型关联判断被打断,没法自动证明`forms.${key}`和当前key对应的属性值类型完全一致,就会触发上述的严格检查,最终得到never类型。
可行修复方案
你可以选任意一种符合代码风格的修复方式:
给reduce回调加泛型约束,让TS建立key和value的类型关联
const forms = keys.reduce(<K extends FormsKey>(result: FormsMap, key: K) => { result[key] = `forms.${key}`; return result; }, {} as FormsMap);这里把回调的key定义为继承自
FormsKey的泛型K,TS就能正确识别`forms.${key}`的类型是`forms.${K}`,正好匹配FormsMap[K]的类型,不会再触发报错。用类型断言明确告诉TS赋值是安全的
如果不想写泛型,可以直接给赋值的右侧加断言,跳过类型检查的不兼容判断:const forms: FormsMap = keys.reduce<FormsMap>((result, key) => { result[key] = `forms.${key}` as FormsMap[typeof key]; return result; }, {} as FormsMap);换用
Object.fromEntries实现相同逻辑
新版本TS对Object.fromEntries结合as const的类型推断支持更好,写法也更简洁:const forms = Object.fromEntries( keys.map(key => [key, `forms.${key}`] as const) ) as FormsMap;
内容的提问来源于stack exchange,提问作者Valerii Zubkov
相关产品推荐
相关产品推荐

