grkmk
grkmk

Reputation: 299

Typescript Error Argument of type 'string | number' is not assignable to parameter of type 'never'

I'm working on a piece of code in Typescript, and came across this below issue that I can't make much sense as to why it's happening.

The below code block triggers an Argument of type 'string | number' is not assignable to parameter of type 'never' error at compile.

interface A {
    x: number | string
}

const a1: A[] = [{x: 1}, {x: 'a'}]
const b: number[] | string[] = ['a', 'b']

const a2 = a1.filter(a => b.includes(a.x))

However; if I were to use (number | string)[] when declaring/assigning b, it works fine.

I checked the definition file for includes (Array<T>.includes(searchElement: never, ...), but that also didn't make sense because I thought that the generic T would encompass number[] | string[].

I would appreciate if someone could shine a light as to why the Array<T> doesn't cover number[] | string[] but covers (number | string)[].

Upvotes: 3

Views: 4350

Answers (1)

Lyubomir Vasilev
Lyubomir Vasilev

Reputation: 3030

The type you set for b is number[] | string[]. This means that its type will be either an array of numbers (number[]) or an array of strings (string[]) - which exactly depends on the data you initialise the variable with.

When you do:

const b: number[] | string[] = ['a', 'b'];

You actually set its type as string[] - this variable b now has nothing to do with numbers and is simply an array of strings.

Then you go ahead and do:

const a2 = a1.filter(a => b.includes(a.x));

So, for each valuе of a1 - which may be a string or a number, you check whether it exists in the array b. And as explained above, b is an array of strings only. And you cannot pass a number | string to includes(), which for this array expects only a string argument (this array is Array<string>). Hence the compiler error.


Now, for the other case you suggest:

const b: (number | string)[] = ['a', 'b'];

This defines an array of the type number | string, that is, every one of its elements can be a different type - either a number or a string. So you can have, for example:

const b: (number | string)[] = [1, 'b'];

It just happens that in your definition, all your elements (the two of them) are the same type - string.

Now when you get to the call to includes(), the situation is very different. Since your array can now hold both numbers and strings, include() would happily work with both those types (this array is Array<number | string>), and a.x can be both types.

Upvotes: 6

Related Questions