Repository: TypeScript
Issue: Member classes with ES2020 private fields do not respect assignment compatibility
Labels: Bug

# 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.
-->
member, class, ES2020, private, field, assignment, compatibility

### 🕗 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 is the behavior in every version I tried starting from 3.8.3.
- I was unable to test this on prior versions because the ES2020 private field syntax was invalid.

### ⏯ 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=3.8.3#code/C4TwDgpgBAwsD2AnAShYBXRA7AKuCAPDlBAB7ARYAmAzlFhAO5QAUAdBwIaIDmNAXFE5YQAbQC6ASigBeAHxCRCmVGJkK1Og2bsuvAYrFTZCgJZYAZhERQAglAD8dqIIYA3awG4AUN4DGADacNHT2AN7eUFFQiBCcVPBYASBQAEKyUIHBdOlhUADEFvDwAISu6AC2AEbWUAC+vtFQFixVgnBIqBjYeJAEwAAWpjSiAOSpo+Jy0nl+iTTwARBsAfA8LKM88MBQFSmpJaMANFBVkp713g3+8zucAAwZ2nY+c1g0dwCMT0wvvgD0-ygAFFSJA-BQqIoSIhEEg2N5AUJ7mx0sIoZxPqihLEoMBGPAoFRTBYrLEsDssiEIHQLHCKkSSWTKDtzANrKZgMI-NAhtZuH4+TQEQ82C1npjUZIgA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
type CtorReturnType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer A ? A : never;

class A {
    readonly B = class B { #foo!: number }

    f(b: CtorReturnType<this['B']>) { console.log('got my B!', b); }
}

const a0 = new A;
const a1 = new A;

// Expected an error.
// a0.B and a1.B are two different classes from different inheritance hierarchies.
a0.f(new a1.B)
```

### 🙁 Actual behavior

Did not produce an error.

### 🙂 Expected behavior

Expected an error stating that `a1.B` is not assignable to `a0.B`.

<!-- What you expected to happen instead, and why -->

Per the handbook:

> Private and protected members in a class affect their compatibility. When an instance of a class is checked for compatibility, if the target type contains a private member, then the source type must also contain a private member that originated from the same class. Likewise, the same applies for an instance with a protected member. This allows a class to be assignment compatible with its super class, **but not with classes from a different inheritance hierarchy which otherwise have the same shape**.