microsoft / TypeScript

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

Array literal of union type should be convertible to union of arrays #38380

Open SLaks opened 4 years ago

SLaks commented 4 years ago

TypeScript Version: v4.0.0-dev.20200505, v3.8.3

Search Terms: array union literal

Code

declare let x: Date | Error;
const y: Date[] | Error[] = [x];

Expected behavior:

No errors.

Array literals of unions should be contextually typed by unions of array literals.

I would also expect [Date | Error] to be convertible to Date[] | Error[], which also fails

Actual behavior:

Type '(Date | Error)[]' is not assignable to type 'Date[] | Error[]'.
  Type '(Date | Error)[]' is not assignable to type 'Date[]'.
    Type 'Date | Error' is not assignable to type 'Date'.
      ...

Playground Link: Link

Motivating real-life(-ish) example: Link

SLaks commented 4 years ago

The real-life example (passing a union to a function accepting a union of arrays) appears to be surprisingly hard to do at all.

So far, I've found just one workaround, but it isn't compatible with exhaustiveness checking :(

RyanCavanaugh commented 4 years ago

We have some logic like this around object literals; it should work on array literals too.

craigphicks commented 6 months ago

For an array the error makes sense because the length is unspecified. For a writable 1-tuple is also makes sense. It is only the special case of a readonly 1-tuple where you should be able to do that conversion.

So this is it

declare const x: Date | Error;
const y:  readonly [Date] |  readonly [Error] = [x] as const;
//       ~  should not be an error on y

Corner case.