类型参数不可分配给参数类型“从不”

目录

Argument of type not assignable to parameter type ‘never’

  1. 类型参数不可分配给参数类型“从不”
  2. 类型不可分配给 TypeScript 中的“从不”类型
  3. 类型不可分配给 React.js 中的“从不”类型

本文涵盖 3 个错误,因此请确保根据您使用的是 TypeScript 还是 React.js 单击与您相关的副标题。

不可分配给参数类型 ‘never’ 的参数类型

当我们声明一个空数组而不显式键入它并尝试向其中添加元素时,会发生错误“Argument of type is not assignable to parameter of type ‘never’”。

要解决该错误,请显式键入空数组,例如
const arr: string[] = [];.

不可分配给参数类型 never

以下是错误发生方式的 2 个示例。

索引.ts
const arr = []; // ⛔️ Error: Argument of type 'number' is not assignable to parameter of type 'never'.ts(2345) arr.push(100); // --------------------------------------- const obj = { arr: [], }; // ⛔️ Argument of type 'string' is not assignable to parameter of type 'never'.ts(2345) obj.arr.push('one');

我们声明了一个空数组,并为它分配了一个类型never[]此类型表示一个永远不会包含任何元素
(始终为空)
的数组

显式键入数组解决错误

要解决该错误,
请显式键入空数组

索引.ts
const arr: number[] = []; arr.push(100); console.log(arr); // 👉️ [100] // --------------------------------------- type MyType = { arr: string[]; }; const obj: MyType = { arr: [], }; obj.arr.push('one'); // 👇️ {arr: ['one']} console.log(obj);

我们将第一个数组键入为number[]. 换句话说,一个只包含数字元素的数组。

索引.ts
const arr: number[] = [];

arr第二个示例中的属性是一个包含字符串 – 的
数组
string[]

我已经写了一篇关于如何在 TS 中为类型化变量声明空数组的详细指南

使用any类型来禁用类型检查

如果您不知道数组包含什么类型的元素并且想禁用类型检查,请将数组键入为any[].

索引.ts
const arr: any[] = []; arr.push(100); arr.push('hello'); arr.push({ name: 'James' }); // 👇️ [100, 'hello', {name: 'James'}] console.log(arr);

这有效地
禁用了类型检查,这意味着数组可以包含任何类型的元素。

输入一个对象数组

下面是一个如何键入
对象数组的示例。

索引.ts
const arr: { id: number; name: string }[] = []; arr.push({ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }); // 👇️ [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}] console.log(arr);

数组中的每个对象都包含idname属性。

您还可以将对象的类型提取到
类型别名
接口中。

索引.ts
type Person = { id: number; name: string; }; const arr: Person[] = []; arr.push({ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }); // 👇️ [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}] console.log(arr);

如果您需要键入一组对象,请查看我的
详细指南

一个空数组被推断为具有一种类型never[]

发生错误是因为当我们声明一个空数组时,TypeScript 将其类型推断为never[]– 一个永远不会包含任何元素的数组。

索引.ts
// 👇️ const arr: never[] const arr = []; // 👇️ const obj: { // arr: never[]; // } const obj = { arr: [], };

tsconfig.json在你的文件中改变这个行为

但是,TypeScript 会根据tsconfig.json文件中的设置以不同方式推断存储空数组的变量类型

当您设置noImplicitAnyfalsestrictNullChecks为时true,空数组的类型被推断为never[]

tsconfig.json文件
{ "compilerOptions": { "strictNullChecks": true, "noImplicitAny": false, // ... rest } }

但是,如果我切换noImplicitAnytrue,存储空数组的变量的类型被推断为any[]

tsconfig.json文件
{ "compilerOptions": { "strictNullChecks": true, "noImplicitAny": true, // ... rest } }

现在arr变量被推断为any[]

索引.ts
// 👇️ const arr: any[] 👇️ const arr = []; // 👇️ const obj: { // arr: never[]; // } const obj = { arr: [], };

请注意,存储空数组的变量现在具有推断类型
any[].

换句话说,一个禁用类型检查的数组(可以包含任何类型的元素)。

但是,对象中的空数组属性仍然是 type never[]

noImplicitAny
选项会导致 TypeScript 在不存在值的类型注释时发出错误,因此它必须
隐式地将
类型推断为any.

这种行为非常不直观,最好不要依赖这样的东西。

最好的做法是在声明时显式键入空数组或对象。

您可以依靠 TypeScript 来推断您声明为内联的文字类型(例如字符串和数字),但对数组或对象这样做绝不是一个好主意。

如果您尝试访问类型为 的值的属性never,您将收到
类型“从不”的属性不存在的
错误。

如果您收到错误Type is not assignable to type ‘never’ in
React.js,请单击以下子标题:

类型不可分配给 TypeScript 中的类型 ‘never’

当我们声明一个空数组而不显式键入它并尝试改变数组时,会出现错误“Type is not assignable to type ‘never’”。

要解决该错误,请显式键入空数组。

type 不可分配给 type never

下面是错误如何发生的示例。

索引.ts
// 👇️ const arr: never[] const arr = []; // ⛔️ Error: Type 'string' is not assignable to type 'never'.ts(2322) arr[0] = 'a';

我们声明了一个空数组,并为它分配了一个类型never[]此类型表示一个永远不会包含任何元素(始终为空)的数组。

显式键入数组解决错误

要解决此问题,请显式键入空数组。

索引.ts
const arr: string[] = []; arr[0] = 'a'; console.log(arr); // 👉️ ['a']

我们将数组键入为string[],换句话说,一个仅包含字符串的数组。

如果您不知道您的数组包含什么类型的元素并且想禁用类型检查,您可以将其键入为any[].

索引.ts
const arr: any[] = []; arr[0] = 'a'; arr[1] = 100; arr[2] = { department: 'development' }; // 👇️ ['a', 100, {department: 'development'}] console.log(arr);

这有效地
禁用了类型检查,这意味着数组可以包含任何类型的元素。

下面是一个如何键入对象数组的示例。

索引.ts
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);

数组中的每个对象都具有namesalary属性。

您还可以将对象的类型提取到
类型别名
接口中。

索引.ts
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'] };

发生错误的原因是当我们声明一个空数组时,TypeScript 将其类型推断为never[]– 一个永远不会包含任何元素的数组。

索引.ts
// 👇️ const arr: never[] const arr = []; // 👇️ const employee: { // tasks: never[]; // } const employee = { tasks: [], };


如果您想阅读更多有关为类型化变量声明空数组的信息,
请查看
以下文章。

noImplicitAny中的设置tsconfig.json

但是,TypeScript 会根据文件中的设置以不同方式推断存储空数组的变量类型tsconfig.json

当您设置noImplicitAnyfalsestrictNullChecks为时true,空数组的类型被推断为never[]

tsconfig.json文件
{ "compilerOptions": { "strictNullChecks": true, "noImplicitAny": false, // ... rest } }

但是,如果我切换noImplicitAnytrue,存储空数组的变量的类型被推断为any[]

tsconfig.json文件
{ "compilerOptions": { "strictNullChecks": true, "noImplicitAny": true, // ... rest } }

现在arr变量被推断为any[]

索引.ts
// 👇️ const arr: any[] const arr = []; // 👇️ const employee: { // tasks: never[]; // } const employee = { tasks: [], };

请注意,存储空数组的变量现在具有推断类型
any[],换句话说,一个禁用类型检查的数组(可以包含任何类型的元素)。

但是,对象中的空数组属性仍然是 type never[]

noImplicitAny
选项会导致 TypeScript 在不存在值的类型注释时发出错误,因此它必须隐式地将其类型推断
any.

这种行为非常不直观,最好不要依赖这样的东西。

在声明对象时显式键入空对象数组始终是最佳做法。

您可以依靠 TypeScript 来推断您声明为内联的文字类型(例如字符串和数字),但对数组或对象这样做绝不是一个好主意。

类型不可分配给 React 中的类型 ‘never’

useState当我们用钩子声明一个空状态数组但不键入数组时,会出现错误“Type is not assignable to type ‘never’” 。

要解决该错误,请使用泛型来键入状态数组。

下面是错误如何发生的示例。

应用程序.tsx
import {useState} from 'react'; function App() { // 👇️ arr is never[] const [arr, setArr] = useState([]); // ⛔️ Error: Type 'number' is not assignable to type 'never'.ts(2322) setArr([1, 2, 3]); return ( <div className="App"> <div>Hello world</div> </div> ); } export default App;

错误是因为我们声明了一个空状态数组而没有显式键入它。

数组的类型被推断为never[],换句话说,一个永远为空的数组,这不是我们想要的。

使用泛型键入状态数组

要解决该错误,请在useState挂钩上使用泛型
来键入状态数组。

应用程序.tsx
import {useState} from 'react'; function App() { // 👇️ type the array with the generic const [arr, setArr] = useState<any[]>([]); setArr([1, 2, 3]); return ( <div className="App"> <div>Hello world</div> </div> ); } export default App;

我们使用了非常广泛的 类型any[],它是一个包含任何类型元素的数组。

在可能的情况下,越具体越好。

应用程序.tsx
import {useState} from 'react'; function App() { // 👇️ array of strings const [strArr, setStrArr] = useState<string[]>([]); // 👇️ an array of objects const [objArr, setObjArr] = useState<{name: string; age: number}[]>([]); setStrArr(['a', 'b', 'c']); setObjArr([{name: 'A', age: 1}]); return ( <div className="App"> <div>Hello world</div> </div> ); } export default App;

上面的示例显示了如何将状态数组键入为字符串数组或对象数组。

使用 TypeScript 时,始终确保在 React 中显式键入空数组。

如果您收到包含
never类型的错误消息,则很有可能您忘记了显式键入一个值,并且它被推断为具有never.

要对此进行调试,请将鼠标悬停在该值上以查看其类型并寻找明确键入它的方法。如果您正在使用 React Hooks,那么很有可能您必须像我们使用 hook 一样使用泛型useState

如果您输入的是基本 TypeScript 变量,只需用冒号分隔变量名称及其类型。

应用程序.tsx
function App() { // 👇️ declare array of strings const arr: string[] = []; arr.push('a', 'b', 'c'); return ( <div className="App"> <div>Hello world</div> </div> ); } export default App;

我还写了一篇关于
如何将 useState 键入为数组或对象的详细文章。

额外资源

您可以通过查看以下教程来了解有关相关主题的更多信息: