microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.07k stars 12.37k forks source link

Adding an overload breaks inference of compositional functions #41066

Open weswigham opened 3 years ago

weswigham commented 3 years ago

Tried fixing this, but ran into another case where an overload breaks type inference:

declare function reverse(a: ReadonlyArray<number>): ReadonlyArray<number>;

declare function incrementEvery(list: ReadonlyArray<number>): ReadonlyArray<number>;
declare function incrementEvery(x: ReadonlySet<number>): ReadonlySet<number>;

declare function compose<T>(
    second: (x: ReadonlyArray<number>) => T,
    first: (x0: ReadonlyArray<number>) => ReadonlyArray<number>,
): (x0: ReadonlyArray<number>) => T;

const works = compose<ReadonlyArray<number>>(incrementEvery, reverse);
const broke: (nums: ReadonlyArray<number>) => ReadonlyArray<number> = compose(incrementEvery, reverse);
src/a.ts(12,79): error TS2345: Argument of type '{ (list: ReadonlyArray<number>): ReadonlyArray<number>; (x: ReadonlySet<number>): ReadonlySet<num...' is not assignable to parameter of type '(x: ReadonlyArray<number>) => ReadonlySet<number>'.
  Type 'ReadonlyArray<number>' is not assignable to type 'ReadonlySet<number>'.
    Property 'has' is missing in type 'ReadonlyArray<number>'.

Unlike the above issue, this was broken in all the way back in 2.0.

Originally posted by @andy-ms in https://github.com/microsoft/TypeScript/issues/23352#issuecomment-380844184

Constantiner commented 3 years ago

This fixes your issue:

const broke: (nums: ReadonlyArray<number>) => ReadonlyArray<number> = compose<ReadonlyArray<number>>(incrementEvery, reverse);