Argument of type not assignable to parameter type 'never'

avatar

Borislav Hadzhiev

Sun Mar 20 20223 min read

banner

Photo by Kieran Osborn

Argument of type not assignable to parameter type 'never' #

The error "Argument of type is not assignable to parameter of type 'never'" occurs when we declare an empty array without explicitly providing a type for it and attempt to add elements to it. To solve the error, explicitly type the empty array, e.g. const arr: string[] = [];.

not assignable to parameter type never

Here are 2 examples of how the error occurs.

index.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');

We declared an empty array and it got assigned a type of never[]. This type represents an array that will never contain any elements (will always be empty).

To solve this, we have to explicitly type the empty array.

index.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);

We typed the first array as number[], in other words an array containing only number elements.

The arr property in the second example is an array containing strings - string[].

If you don't know what type of elements your array contains and would like to disable type checking, you can type it as any[].

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

This effectively disables type checking, which means the array can contain elements of any type.

Here is an example of how you would type an array of objects.

index.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);

Each object in the array contains the id and name properties.

You can also extract the type of the object into a type alias or an interface.

index.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);

The reason the error "Argument of type is not assignable to parameter of type 'never'" occurs is because when we declare an empty object, TypeScript infers its type to be never[] - an array that will never contain any elements.

index.ts
// 👇️ const arr: never[] const arr = []; // 👇️ const obj: { // arr: never[]; // } const obj = { arr: [], };
However, TypeScript infers the type of the variables that store an empty array differently depending on the settings in your tsconfig.json file.

When you set noImplicitAny to false and strictNullChecks to true, the type of an empty array is inferred to be never[].

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

However, if I switch noImplicitAny to true, the type of a variable that stores an empty array is inferred to be any[].

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

Now the arr variable is inferred to be any[].

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

Notice that variables that store an empty array now have an inferred type of any[], in other words an array with type checking disabled (can contain any type of elements).

However, the empty array property in the object is still of type never[].

The noImplicitAny option causes TypeScript to issue an error when no type annotations for a value are present, so it has to implicitly infer its type to any.

This behavior is very unintuitive and it's best to not rely on something like this.

It is always a best practice to explicitly type empty arrays of objects when you declare them.

You can rely on TypeScript to infer the type of literals (e.g. strings and numbers) that you declare inline, but it's never a good idea to do that for arrays or objects.

Use the search field on my Home Page to filter through my more than 1,000 articles.