Reputation: 299
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
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