Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is "Types of parameters '__0' and 'value' are incompatible" a bug?

Tags:

typescript

This type-checks in TypeScript Playground, but fails on v3.1.6:

function head([a]) {
  return a;
}

const x: number[] = [[1], [2]].map(head)

Error mesage:

server/src/mock-resolvers/mock-data.ts(549,36): error TS2345: Argument of type '([a]: [any]) => any' is not assignable to parameter of type '(value: number[], index: number, array: number[][]) => any'.
  Types of parameters '__0' and 'value' are incompatible.
    Type 'number[]' is not assignable to type '[any]'.
      Property '0' is missing in type 'number[]'.

Is this a bug? I don't understand the error message or see what's wrong with the code.

Being more specific with the types doesn't help, I get a similar error if the function is defined like this:

function head([a, _b]: [number, number]): number {
  return a;
}
like image 675
Max Heiber Avatar asked Oct 20 '25 08:10

Max Heiber


1 Answers

You can reproduce the error if you enable strictFunctionTypes in the playground. You can read more about this option here but the gist of it is that it removes bi-variance from functions.

In your case the array [[1], [2]] is not typed as Array<[number]>, but rather it is typed as Array<number[]>, since typescript does not infer tuple types for array literals unless it is directed to do so. This causes an error because your function is explicit about accepting a the tuple type [any]. An array type is not assignable to a tuple with a single element (even a tuple of any).

The simplest solution is to specify the type of the array explicitly:

function head([a] : [number]) { // type is not required but it's best to not leave implict any 
  return a;
}

const data: Array<[number]> = [[1], [2]]
const x: number[] = data.map(head)

You can create a helper function that will infer tuples from the argument type:

function tuple<T extends any[]>(...a: T) {
  return a;
}

const x: number[] = [tuple(1), tuple(2)].map(head)

Or infer directly an array of tuples:

function tupleArray<T extends [any]|any[]>(...a: T[]) {
  return a;
}

const x: number[] = tupleArray([1], [2]).map(head)
like image 158
Titian Cernicova-Dragomir Avatar answered Oct 22 '25 00:10

Titian Cernicova-Dragomir



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!