Skip to content

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

Closed
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions