How to concat array of the union type in typescript?
When I try to use concat
with the array of union type, I got this error:
This expression is not callable. Each member of the union type '{ (...items: ConcatArray<{...}>[]): { ... }[]; (...items: ({ ... } | ConcatArray<{ ...; }>)[]): { ...; }[]; } | { ...; }' has signatures, but none of those signatures are compatible with each other.
CodeSandbox: https://codesandbox.io/s/modern-breeze-qt9mb?file=/src/index.ts
Code example:
const arr1 = [
{ val1: 1, val2: 2, val3: 3 },
{ val1: 11, val2: 22, val3: 33 }
];
const arr2 = [
{ val1a: "1a", val2a: "2a", val3a: "3a" },
{ val1a: "11a", val2a: "22a", val3a: "33a" }
];
const arr3 = [
{ foo: "lfsfs", bar: "fabgg" },
{ foo: "l414g", bar: "fahrh" }
];
function getRandomArr() {
if (Math.random() < 0.5) {
return arr2;
} else {
return arr1;
}
}
//error
const FinalArr = getRandomArr().concat(arr3);
You are following a red herring. Your problem has nothing to do with "arrays of the union type". The problem is that all of the arrays you are trying to concat
have elements of different types, and concat
requires that the arrays have elements of the same type T
:
Array<T> {
concat(...items: ConcatArray<T>[]): T[];
concat(...items: (T | ConcatArray<T>)[]): T[];
}
The above is from lib.es5.d.ts
.
You can quickly simplify the problem and remove the red herring by trying the following code and understanding the error messages:
const a = arr1.concat(arr3) // error
const b = arr2.concat(arr3) // error
You original error message was also telling you this: "Each member of the union type... has signatures, but none of those signatures are compatible with each other."
The only reason 'union type' is mentioned in the error message is because the message wants to tell you about the types that are incompatible, and the return type of getRandomArr()
is a union type (by inference).
There are countless ways you can fix your code. Choose the one that makes the most sense from a type safety perspective. Here are some examples:
If you care about the types of the various arrays involved, be explicit. Say you want your first three arrays to retain their specific types and their type safety, and you just want FinalArr to be able to handle elements of all three array element types. You could do this:
type FinalElemType
= typeof arr1[number] | typeof arr2[number] | typeof arr3[number]
function getRandomArr(): FinalElemType[] {
...
}
This will result in FinalArr
also having the type FinalElemType[]
. No errors, and you are being explicit about types and thus have type-safe code, assuming the types you are using are purposeful rather than hacks just to get errors to go away.
unknown[]
or any[]
If you don't care that the arrays have elements of different types, simply let Typescript know. For example, if you change the types of your first two arrays as follows, the concat won't complain. Inspect the types of all the elements and getRandomArr
to understand what is going on.
const arr1: unknown[] = [
{ val1: 1, val2: 2, val3: 3 },
{ val1: 11, val2: 22, val3: 33 }
];
const arr2: unknown[] = [
{ val1a: "1a", val2a: "2a", val3a: "3a" },
{ val1a: "11a", val2a: "22a", val3a: "33a" }
];
getRandomArr
's return type will also become unknown[]
, and it will allow you to concat any other array to it.
Or if you want arr1
thru arr3
to retain their type safety, and only don't care about the type of getRandomArr
and FinalArr
, you could do this:
const FinalArr = (getRandomArr() as any[]).concat(arr3);
As @jsejcksn recommends, "Use spread syntax to combine the arrays", "See tsplay.dev/wOzdRW". This allows you to concat arrays with mixed element types:
const FinalArr = [...getRandomArr(), ...arr3];