TypeScript 中 Type is not assignable to type ‘never’ 错误
当我们声明一个空数组而不显式键入它并尝试改变数组时,会出现错误“Type is not assignable to type ‘never’ ”。 要解决该错误,需要显式键入空数组,例如 const arr: string[] = [];
。
下面是产生上述错误的示例代码
// 👇️ const arr: never[]
const arr = [];
// ⛔️ Error: Type 'string' is not assignable to type 'never'.ts(2322)
arr[0] = 'a';
我们声明了一个空数组,它被分配了一个 never[]
类型。 此类型表示一个永远不会包含任何元素(始终为空)的数组。
为了解决这个问题,我们必须显式键入空数组。
const arr: string[] = [];
arr[0] = 'a';
console.log(arr); // 👉️ ['a']
我们将数组键入为 string[]
,换句话说,一个仅包含字符串的数组。
如果我们不知道数组包含什么类型的元素并且想禁用类型检查,我们可以将其键入为 any[]
。
const arr: any[] = [];
arr[0] = 'a';
arr[1] = 100;
arr[2] = { department: 'development' };
// 👇️ ['a', 100, {department: 'development'}]
console.log(arr);
这有效地禁用了类型检查,这意味着数组可以包含任何类型的元素。
下面是一个如何键入对象数组的示例。
const arr: { name: string; salary: number }[] = [];
arr[0] = { name: 'Tom', salary: 100 };
arr[1] = { name: 'Tim', salary: 200 };
// 👇️ [{name: 'Tom', salary: 100}, {name: 'Tim', salary: 200}]
console.log(arr);
数组中的每个对象都有 name
和 salary
属性。
我们还可以将对象的类型提取到类型别名或接口中。
type Employee = {
name: string;
salary: number;
tasks: string[];
};
const arr: Employee[] = [];
arr[0] = { name: 'Tom', salary: 100, tasks: ['task 1'] };
arr[1] = { name: 'Tim', salary: 200, tasks: ['task 2', 'task 3'] };
出现错误“Argument of type is not assignable to parameter of type ‘never’ ”的原因是,当我们声明一个空对象时,TypeScript 将其类型推断为 never[]
——一个永远不会包含任何元素的数组。
// 👇️ const arr: never[]
const arr = [];
// 👇️ const employee: {
// tasks: never[];
// }
const employee = {
tasks: [],
};
但是,TypeScript 会根据
tsconfig.json
文件中的设置以不同方式推断存储空数组的变量类型。
当我们将 noImplicitAny
设置为 false 并将 strictNullChecks
设置为 true 时,空数组的类型将被推断为 never[]
。
{
"compilerOptions": {
"strictNullChecks": true,
"noImplicitAny": false,
// ... rest
}
}
但是,如果我将 noImplicitAny
切换为 true,存储空数组的变量类型将被推断为 any[]
。
{
"compilerOptions": {
"strictNullChecks": true,
"noImplicitAny": true,
// ... rest
}
}
现在 arr 变量被推断为 any[]
。
// 👇️ const arr: any[]
const arr = [];
// 👇️ const employee: {
// tasks: never[];
// }
const employee = {
tasks: [],
};
请注意
,存储空数组的变量现在具有any[]
的推断类型,换句话说,一个禁用类型检查的数组(可以包含任何类型的元素)。
但是,对象中的空数组属性仍然是never[]类型。
noImplicitAny
选项会导致 TypeScript 在不存在值的类型注释时发出错误,因此它必须隐式地将其类型推断为 any
。
这种行为非常不直观,最好不要依赖这样的东西。
在声明对象时显式键入空对象数组始终是最佳做法。
我们可以依靠 TypeScript 来推断声明为内联的文字类型(例如字符串和数字),但对数组或对象这样做绝不是一个好主意。