Repository: TypeScript
Issue: Generic should expand in union
Labels: Needs Investigation,Rescheduled

# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

<!--
  What search terms did you use when trying to find an existing bug report?
  List them here so people in the future can find this one more easily.
-->
generic expansion, union expansion

### 🕗 Version & Regression Information

<!-- When did you start seeing this bug occur?

"Bugs" that have existed in TS for a long time are very likely to be FAQs; refer to
  https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

If possible, please try testing the nightly version of TS to see if it's already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly

Note: The TypeScript Playground can be used to try older versions of TypeScript.

Please keep and fill in the line that best applies:
-->
- This changed between versions 4.1.5 and 4.2.3 (and the new behavior remains in 4.3.0-dev.20210407)

### ⏯ Playground Link

<!--
  A link to a TypeScript Playground "Share" link which shows this behavior

  The TypeScript Workbench can be used for more complex setups, try
  https://www.typescriptlang.org/dev/bug-workbench/

  As a last resort, you can link to a repo, but these will be slower for us to investigate.
-->
* [Playground link with an example of the regression](https://www.typescriptlang.org/play?jsx=0&ts=4.2.3#code/C4TwDgpgBAsghiARhAPAFQHxQLwCgoFQA+UAdgK4A2l+hJauuAxgPakDOwUAluwEoR2LSgDcIAExxR0GABQBbBMgBcsJakwBKVYqTReUNDgy0Cu5FACE2bGSqUA3I1YcuisFPQAaKAFU5plDmEKrwejJege4AYqSqsiJwlOQhhprGfpHaauH+GbwCQqISCurpAPxBcGCxpXrpOupOuAD0LX7s3KQA5lBwpH0AToMIPAPAABYGEAAecPJglNDITHDk7PpucADWglCT0ABmcNzJg9AsiCLcLOtQAO4TEAPsYOdw4l293MCRbVCIchcA5QN6XJaKYDcJgAiATODXFiDHjsMgsLivCBMbiHaH7FhDEYgdgAOlw4ixlDg5ygLk4UEOLBYoXUKDCyBQnEGXwA2gBdDAYJzuWSMlg+LjYLA8kmy4B8zQOKD-LgGLm8vljKAAFhJAEYfOzUOqevysLJ+pIIMMkVAAEzagAcjvSXR1JLtZJFYp8smAqhN3X56Sl+0VyvaqtRgf5WsQ6Im7r1fVIkl1doeP0TIP6pHRcChbBJQA)
* [Playground link with a workaround](https://www.typescriptlang.org/play?jsx=0&ts=4.2.3#code/C4TwDgpgBAsghiARhAPAFQHxQLwCgoFQA+UAdgK4A2l+hJauuAxgPakDOwUAluwEoR2LSgDcIAExxR0GABQBbBMgBcsJakwBKVYqTReUNDgy0Cu5FACE2bGSqUA3IwD0zwyyhxgwCPLBdgDwAnQWExKGAAC312dnJ9UlxXKEjvMHZlVwB3HIA6UEh2JiDuf0o4UgBzXJYgyucwcpAAfgArdgAPbAAGADJgdmwAFlyAJlyAZgBiVnEIZwBhIbQsgBFKsEqAIQBBdkrI7h2+SJ2ABR2AMQBFAAkO64AZLIXKlhudgGoAVR3xSoA0kMdqNKJ9IgApODkcg7DqVM5wADWqwA8llfpRyFkAKIsPijR4AZUqqyYAEkdjiOh0+N0AOI7LbXLaILYwbZMdhQpFZLYAgBqAE0AI5oATfABy6xA3QW5AArJcdgscaNEPSiSLfhNyQBGIVMci8S5na47OAAq7fBWNVbyHEAoJZCCtCEQSoQYGirXsbgQrKUVHXSKRMBBekAMzAtzg0Nun3piBe1xF5KJ8qCYHOHS2THpCw6YAAGlnUeQwOWdqtuo9iwB2dgTAHmhWULZZGPdHZoFgwckXC5MoX0nE7HYQJhnCGVSjS8loW6rJH1s5gchMasAdVnCzQ3a28iYkoAXjOAJx7bgLR5MR6o4Dm1HLMdndhC1HiLJDSijc8TGAFj4RABQWckmEiTcFWuSUADZiyhAEhTJGcdiONBUVWYtLm4VZbnaDl2EebgRAWdlEG4WNbnrS5IlWHEhUqf4dlRShv24DpKHWBUQEqR4kSGb4cVRR4tiFFhi2+AFVgWEBmVIHF6WLLIQW2cRVh2IUIRPcgtyJGBKEqT5HlaIVHh2AAOJF5BAIYtgsk9rlRaSAFpHkqelHnkCyREoVorSuSEqSFSNURPb5URFCARBAIiIU+MByXJGAYCRAVxxxE84EqHYmFaEQiWLPg9QhR5gAALQhS4hTACz2HkHYRUiSUJmLBVYKJMFugFEARDgEVgD4SpIwVLd2GuWDyXkesgj1SMBXJJFKD1cQWAgM5ujQAdYJjPgmAWSI2Qhc0kjcF0oGKCAvGgCooHIUgsiCOAwEgIIInACAABpPFISRyHYfQuG4UgoAAA0UMBQagZBKBYLJclwApoG+B6nrAeA9HQKAIA6HxfvYNRMfupFSDh0gMCwWwjBxvHxAJjHkBQUweFISMIDe75cBMQgoGaKBqSYLE5hQb5vooagsGSLJIhAC6KgAci4c7Wn+rhVrB75QeabXmdUUhovZpxmDYTgoAhqR0G+745GZ8wIFUBmNAwT7beey5SFUWQ+qxe2oBRx7nsdmRNGMP2Xe0QnGet0PeAEIRRAkBR1BDvmIfdpO9E8An-bRoOtCgHR1CNuZBbgEILpNrhIxYFgHfUFAg84EoqgAbQAXQppwIdkauWG+rhsCwFvchH4A280BwoGSIGCab4HKnb76hDu1HnrAeeoCyWokQkFw3C2cguFJrIIkOAm2GgRAghYHflFwSN7qYYBuDYbGOjgPxKFQAU5BEOvMZ-iHAA3szL+XBvbxH-ozH+TgeasA4FwEIcBJC2BQJcN+tMCY7xACwSMUAf4924BASg4hVCXAjkHAULdLgd2MMzHm3cIFfSgCIUOIgW6RiISQ8eU83BoA+lAeWlx5Zy1IKTLgFh-oSAiB4YGcwOjvUgIInOgd64-3lrkWQowFQTFgpoXAABfIAA), that causes other problems, but still probably relevant.

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
type Maybe<T> =
    | null
    | T

const isResolved = <T>(maybe: Maybe<T>): maybe is T =>
    maybe !== null;

const map = <T, U>(
    maybe: Maybe<T>,
    mapFn: (value: T) => U,
): Maybe<U> => isResolved(maybe) ? mapFn(maybe) : maybe;

// Using an array in this example because it makes the failure obvious when spreading it,
// but the problematic behavior is not specific to arrays.
declare const foo: Maybe<Maybe<string[]>>;
map(foo, t => [...t]); // t is string[] in 4.1, Maybe<string[]> (and error 2488) in 4.2.
map(foo, (t: string[]) => t); // t is string[] in both 4.1 and 4.2 with the annotation.
```

### 🙁 Actual behavior

<!-- What happened, and why it was wrong -->
`t` in `map(foo, t => [...t]);` is a `Maybe<string[]>`.

It seems like when `T` in `Maybe` is another `Maybe`, it's opaque (not expanded).

### 🙂 Expected behavior
`t` in `map(foo, t => [...t]);` is a `string[]`.

It seems like when `T` in `Maybe` is another `Maybe`, it's expanded. For example `Maybe<Maybe<string[]>`> is expanded to `null | (null | string [])`, then collapsed to `null | string[]`, which is the same as `Maybe<string[]>`.

It seems like this is the desired behavior, because at runtime, `t` will indeed only ever be `string[]`.

<!-- What you expected to happen instead, and why -->