Skip to content

Each member of the union type has signatures, but none of those signatures are compatible with each other #33591

@ackvf

Description

@ackvf

TypeScript Version: 3.6.3

Search Terms:
array.map, expression is not callable, union type signatures,

Code

The following code is the exact same code as in this codesandbox
https://codesandbox.io/s/lingering-sun-7itgj

interface Product_result {
  __typename: 'Product'
  id: number
  description: string | null
}
interface Campaign_result {
  __typename: 'Campaign'
  id: number
  products: (Product_result | null)[] | null
}


interface Product {
  id: number
  description: string
  specific: boolean
}
interface Campaign {
  products: Product[]
}

type CompoundType = Campaign_result | Campaign

/* --- */

const props: { campaign?: Campaign_result } = {}
const emptyCampaign: Campaign = {
  products: []
}

const initialData: CompoundType = props.campaign || emptyCampaign


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

product inside map is any, but I know `id` is there
*/
initialData.products.map(product => product.id)


// product is { description: string, id: number } - as expected
const product = initialData.products[0] 

// product inside map is { description: string, id: number } - as expected
;(initialData.products as Array<CompoundType['products'][0]>).map(product => product.id)


/* interestingly */

type T01 = Array<CompoundType['products'][0]>   // T01: (Product_result | Product)[]  -  I can actually have mix of both. Products that were fetched and Products added via a Form
type T02 = CompoundType['products']             // T02: Product_result[] | Product[]

declare const v1: T01
v1.map(product => product) // OK

declare const v2: T02
v2.map(product => product) // NOK

Expected behavior:

I know id is there, so this should work
initialData.products.map(product => product.id)

This workaround works
(initialData.products as Array<CompoundType['products'][0]>).map(product => product.id)

Actual behavior:

The map gives a non compatible call signature error (as in the snippet above), and the product inside is any.

Related
TypeScript 3.3 - Improved behavior for calling union types
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-3.html#caveats

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions