merito
merito

Reputation: 485

why typescript disallow call concat in string | string[] type?

const s: string = 'foo';

const pass1 = (origin: string) => origin.concat(s);
const pass2 = (origin: string[]) => origin.concat(s);

type S = string | string[];

const error = (origin: S) => origin.concat(s);

The code above. I can call concat in a string or string[] type. So why TypeScript disallow call concat in string | string[] type?

The error is:

Cannot invoke an expression whose type lacks a call signature.
Type '((...strings: string[]) => string) | { (...items: ConcatArray<string>[]): string[]; (...items: (s...'
has no compatible call signatures.

Because they have different return type? But I think TS can infer error's type is S. Is it a intentional design? If it is, why?

Upvotes: 3

Views: 1998

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249486

Because while the concat method is common between the two types it has a very different signature between the two, so Typescript can't really merge the declarations of the methods. While not ideal you can use a type guard to discern between the two types:

const s: string = 'foo';
type S = string | string[];

const error = (origin: S) => typeof origin === 'string' ?
    origin.concat(s) :
    origin.concat(s);

Or just assert as any :

const s: string = 'foo';
type S = string | string[];

const error = (origin: S) =>  (origin as any).concat(s) as S

There is also the option of transforming the union of signatures into an intersection of signatures. This may work well in some cases but not in others:

const s: string = 'foo';
type S = string | string[];

type UnionToIntersection<U> = 
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

function mergeSignature<T, K extends keyof T> (value: T, method: K) : UnionToIntersection<T[K]>{
    return ((...args: any[]) => (value[method] as any as Function).apply(value, args)) as any;
}

const error = (origin: S) => mergeSignature(origin, 'concat')(s); 

Upvotes: 5

Related Questions