Typescript: Allow array `concat` to concat arrays of different types

Created on 12 May 2019  路  4Comments  路  Source: microsoft/TypeScript

TypeScript Version: 3.5.0-dev.20190511

Code

[0].concat('')
// Argument of type '""' is not assignable to parameter of type 'number | ConcatArray<number>'.

Expected behavior:
The concated array has type (number|string)[].

Actual behavior:
Error.

Possible fix:
In https://github.com/microsoft/TypeScript/blob/b7fe99a88c59bd652029bdfe5b6ba8709a677838/lib/lib.es5.d.ts#L1231

interface Array<T> {
- concat(...items: ConcatArray<T>[]): T[];
+ concat<U>(...items: ConcatArray<U>[]): (T|U)[];

Playground Link:
https://www.typescriptlang.org/play/#src=%5B0%5D.concat(%5B''%5D)

Related Issues:

29604

Search Terms:
array concat

Duplicate

Most helpful comment

I have hit this issue while developing a Vue.js component that accepts a value property which can be of type string | string[] | number | number[].

It is an option-list type component that allows a user to select either a single or multiple options from a given list, the options being indexed by string or number ids. The reason I'm not only accepting arrays as the value prop is that the component is bound directly to my form model, which is in turn created automatically from the view model, so keeping proper value type was a requirement.

Within the component however, it is handy to always work with the prop as an array, so I created a simple getter using the `[].concat()' trick. No biggie in vanilla JS but turned out to be an issue with TS. I have dealt with it like so:

get valueArray(): string[] | number[] {  
    return ([] as (string | number)[]).concat(this.value || []) as string[] | number[];  
}

All 4 comments

You can always use declaration merging to add a generic overload to Array.concat() if you find it useful in your own code:

// declaration merge
interface Array<T> {
    concat<U>(...items: (U | ConcatArray<U>)[]): (T | U)[]
}

const okay = [0].concat("");  // Array<string | number>

Playground link

Or, you can widen the array element type yourself before concating to it:

const okay = [0 as string | number].concat(''); // Array<string | number>

Playground link

Before the standard library is modified for everyone, though, you'd want to establish that this use case is common enough in real-world code to warrant it. The compiler tries to catch potential bugs. For real uses of concat() in the wild, what is the false-positive (the compiler thinks good code is a bug) rate of the current typings, and how does that compare to the false-negative (the compiler doesn't catch a bug) rate of the proposed typings?

Duplicate #26378

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

I have hit this issue while developing a Vue.js component that accepts a value property which can be of type string | string[] | number | number[].

It is an option-list type component that allows a user to select either a single or multiple options from a given list, the options being indexed by string or number ids. The reason I'm not only accepting arrays as the value prop is that the component is bound directly to my form model, which is in turn created automatically from the view model, so keeping proper value type was a requirement.

Within the component however, it is handy to always work with the prop as an array, so I created a simple getter using the `[].concat()' trick. No biggie in vanilla JS but turned out to be an issue with TS. I have dealt with it like so:

get valueArray(): string[] | number[] {  
    return ([] as (string | number)[]).concat(this.value || []) as string[] | number[];  
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

MartynasZilinskas picture MartynasZilinskas  路  3Comments

zhuravlikjb picture zhuravlikjb  路  3Comments

wmaurer picture wmaurer  路  3Comments

seanzer picture seanzer  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments