1

With the code below:

interface DataOne {
    strings: string[],
}

interface DataTwo {
    numbers: number[],
}

const Component = (onDataReceived: (data: DataOne | DataTwo) => void) => {
    const data: DataOne | DataTwo = {numbers: [1, 2, 3]}
    onDataReceived(data)
}

const onDataOneReceived = (data: DataOne) => console.log(data)
Component(onDataOneReceived)

I get the following compile error:

Argument of type '(data: DataOne) => void' is not assignable to parameter of type '(data: DataOne | DataTwo) => void'. Types of parameters 'data' and 'data' are incompatible. Type 'DataOne | DataTwo' is not assignable to type 'DataOne'. Property 'strings' is missing in type 'DataTwo' but required in type 'DataOne'.

I tried solving it by introducing type guards (narrowing) and generic types for both Component and onDataReceived, but to no avail. Could someone guide how this can be fixed?

barciewicz
  • 3,511
  • 6
  • 32
  • 72

1 Answers1

0

This is because of contravariance. See this example:

interface DataOne {
  strings: string[],
}

interface DataTwo {
  numbers: number[],
}

declare let a: DataOne | DataTwo
declare let b: DataOne

a = b // ok

let fnA = (data: DataOne | DataTwo) => {
  data
}
let fnB = (data: DataOne) => { }

fnA = fnB // error

Playground

In first example, b is assignable to a, however in second example is not. Function arguments are in contravariant position. See this question/answer for more explanation about *-variance.