Typescript: Union types not correctly handled in array.map

Created on 8 Mar 2019  路  4Comments  路  Source: microsoft/TypeScript


TypeScript Version: playground / 3..3.333


Search Terms:
union type, array map

Code

function flattenStringArrays(values: string | string[] | string[][]): string{

    if (Array.isArray(values)) {
        return values.map(value => flattenStringArrays(value)).join("");
    } else {
        return values;
    }
}

Expected behavior:
here the value in the map expression should be of type string[] | string[][]

Actual behavior:
Compilation error thrown:

Cannot invoke an expression whose type lacks a call signature. Type '((callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: string[], index: number, array: string[][]) =>
U, thisArg?: any) => U[])' has no compatible call signatures.

Playground Link:
link

Related Issues:

Duplicate

Most helpful comment

Here's a workaround:

/** Type workaround for https://github.com/Microsoft/TypeScript/issues/7294#issuecomment-465794460 */
type ArrayElem<A> = A extends Array<infer Elem> ? Elem : never

export function elemT<T>(array: T): Array<ArrayElem<T>> {
  return array as any
}

Example usage:

type A = { x: number, y: string }
type B = { x: number, z: string }
type Subject = A[] | B[]

function foo (items: Subject) {
  // items.map(item => item.x) // Type error
  elemT(items).map(item => item.x) // Works!
}

All 4 comments

This is a workaround for the issue:

function flattenStringArrays(values: string | (string | string[])[]): string{

    if (Array.isArray(values)) {
        return values.map(value => flattenStringArrays(value)).join("");
    } else {
        return values;
    }
}

link

This is a design limitation because it's trying to combine two generic union signatures. See these comments

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

Here's a workaround:

/** Type workaround for https://github.com/Microsoft/TypeScript/issues/7294#issuecomment-465794460 */
type ArrayElem<A> = A extends Array<infer Elem> ? Elem : never

export function elemT<T>(array: T): Array<ArrayElem<T>> {
  return array as any
}

Example usage:

type A = { x: number, y: string }
type B = { x: number, z: string }
type Subject = A[] | B[]

function foo (items: Subject) {
  // items.map(item => item.x) // Type error
  elemT(items).map(item => item.x) // Works!
}
Was this page helpful?
0 / 5 - 0 ratings