Repository: TypeScript
Issue: Better error messaging for when property assignments fail due to intersection types
Labels: Suggestion,Experience Enhancement

# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

`error messaging`
`not assignable to type 'never'`
<!--
  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.
-->

### 🕗 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 isn't an error, just a confusing error message for a corner case, so it's been in TypeScript for a while.

### ⏯ 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 relevant code](https://www.typescriptlang.org/play?ts=4.1.3#code/JYOwLgpgTgZghgYwgAgArQM4HsTIN4BQyyIcAthAFzIZhSgDmA3EcnA1SQK5kBG0LAL4ECMLiARhgOZAiwAHAJ7oo2EAAos9BqDgAbairUAaWQsUAVLIcw4AlPlYwtydXJC1kAawiLkWGGQAbQAiUgoQ0xD2CBCAXTYMMw8wB0JiYjklKyCfRQSAXn9tXT1c3zjWYWFRcUlpXCzlOCgpfSMcTRLSAzQWtr0AHg6QAD5TJqtDfuB9YdsxtKcXNxxPPP9A0PDYqJj4xOTaJYyzbKxy-OQirWAdHsvK4mqCIA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
interface Person {
  name: string;
  age: number;
}

function copyPerson(original: Person, copyTo: Person) {
  for (const key of ["name", "age"] as const) {
    // Type 'string | number' is not assignable to type 'never'.
    //   Type 'string' is not assignable to type 'never'. (2322)
    copyTo[key] = original[key]; // error on copyTo[key]
  }
}

function copyPartialPerson(original: Partial<Person>, copyTo: Partial<Person>) {
  for (const key of ["name", "age"] as const) {
    // Type 'string | number | undefined' is not assignable to type 'undefined'.
    //   Type 'string' is not assignable to type 'undefined'. (2322)
    copyTo[key] = original[key]; // error on copyTo[key]
  }
}

```

### 🙁 Actual behavior

The error messages shown in the code above.

### 🙂 Expected behavior

An error message indicating that the right-hand side of the assignment must be assignable to the intersection of all possible types of the left-hand side of the assignment. The intersection part is specifically what seems to be hard to intuit about this error the first time someone encounters it. The `never` and `undefined` types being assigned to in the examples above seem to come out of nowhere.

One option is to add another level of messaging to the error, e.g.
```
Type 'string | number' is not assignable to type 'string & number'.
  Type 'string | number' is not assignable to type 'never'.
    Type 'string' is not assignable to type 'never'.
```

```
Type 'string | number | undefined' is not assignable to type '(string | undefined) & (number | undefined)'.
  Type 'string | number | undefined' is not assignable to type 'undefined'.
    Type 'string' is not assignable to type 'undefined'.
```

Another option is to special-case assignments that assign to `$expr1[$expr2]`, and have an error message like `Cannot assign type $assigneeType to $expr1[$expr2] for all values of $expr2.` e.g.

```
Cannot assign type 'string | number' to 'copyTo[key]' for all possible values of 'key'.
  Type 'string | number' is not assignable to type 'never'.
    Type 'string' is not assignable to type 'never'.
```

```
Cannot assign type 'string | number | undefined' to 'copyTo[key]' for all possible values of 'key'.
  Type 'string | number | undefined' is not assignable to type 'undefined'.
    Type 'string' is not assignable to type 'undefined'.
```

That feels nicer, but we wouldn't want to have that error message any time a bad assignment is made to an index access. To only show the message at the appropriate time, a second check might be necessary, where the type-checker checks if the right-hand side would be assignable to the "read" type of the left-hand side. As in, if the following code would work:
```
let val = leftHandSideExpression;
val = rightHandSideExpression;
```
Then we can guess that the user is probably encountering this specific issue.