TypeScript-eslint报错'Unsafe assignment of an error typed value'解析
问题代码
const map = { 0.1: 'bar', }; const x = Math.random(); // ESLint: Unsafe assignment of an error typed value.(@typescript-eslint/no-unsafe-assignment) const s: string = map[x]; console.log(s);
ESLint配置
{ "rules": { "@typescript-eslint/no-unsafe-assignment": "error" } }
问题解答
1. 报错触发原因
TypeScript对对象字面量的类型推断是精确字面量类型:当定义const map = { 0.1: 'bar' }时,TypeScript会将其推断为{ 0.1: string },即这个对象的键被严格限定为0.1这个具体数值,而非任意number类型。
当用Math.random()返回的任意number值去索引该对象时,TypeScript无法确认这个键是否存在于map中,此时map[x]的类型被推断为string | undefined。而@typescript-eslint/no-unsafe-assignment规则的核心是阻止类型不兼容的赋值操作,你将一个可能为undefined的变量赋值给明确声明为string类型的s,类型不匹配,因此触发报错。
2. “错误类型值”具体指什么
这里的“错误类型值”指的是map[x]的推断类型string | undefined,它与你为s声明的string类型不兼容。规则认为这种将包含非预期类型(undefined)的值赋值给严格类型变量的操作存在风险,因此标记为“不安全赋值”。
补充:为何显式声明Record<number, string>能解决问题?
当你将map显式声明为Record<number, string>时,TypeScript会认定该对象可以接受任意number类型的键,且对应值均为string类型(TypeScript会暂时忽略“键是否实际存在”的检查,这是Record类型的特性)。此时map[x]的类型被推断为string,与s的类型完全匹配,规则不再触发报错。
你提到的“s最多只会被赋值undefined”是运行时逻辑,但TypeScript的静态类型检查(包括这条ESLint规则)基于编译时类型推断。在编译阶段,当map被推断为精确字面量类型时,map[x]的类型是string | undefined,与string类型不兼容,因此规则会触发报错——规则关注的是类型兼容性,而非运行时实际值的可能性。
内容的提问来源于stack exchange,提问作者Dan Dascalescu

