Repository: TypeScript
Issue: Discriminated union not narrowing when mixing finite and infinite domain types in a single field
Labels: Suggestion,Help Wanted,Experience Enhancement

# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

discriminated union narrowing infinite finite domain

### 🕗 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 (3.3.3, 4.9.4, and nightly), and I reviewed the FAQ for entries about narrowing and unions

### ⏯ 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.9.4#code/KYDwDg9gTgLgBASwHY2FAZgQwMbDgOQiWAFlgYoFs4BvAWACg44phMATIgGwE84BXJAhgAuOACJCxcQG5GzVh258Abpi79gYpPwC2AIzRyGAX0aNQkWHBg8weACL8omGAiJkKVOAF5a8ljZOJF4BIVEJAGVgbCJ2AGdZRhNjC3BoeFt7OABRKChoT0pqP3omQKUQvkFhMXE8gqgkhgCAela4ACFgLggAdxs7YHi4TFY4dGRhYBkbAAtgPjBWFWAUebwAAxqYTYmEHvYJgt04dgR47EpdZFdkAHMNsPckRFeYBbhN+PtsPYh9AArGIwAKKYKhNQaLRwADkWBg6lhcAAPnC0I1kWjYX0xkIkPdYcZmO0KhDVOpNGIAAyouAARmJcFJ4OUcChVLg+ggEC4bCQTJZQTZHJhOi4XDpgnYwEmxHYqXKpO6vQGWWGo3GyDl01C8QQAC9gAqNvE8H0EBK4PcEKs4DwIPwnudLtdbm4CVzgHNMCp3FB7Y64JYQW0OqyquzKTD4l4CYLw8LI6LtHpDFAE2SRdGxJgkDxMxHITm4ABBfKYHgAHmpAD5jClzAxLBlBtkilQcqt1n4pKRyMU6U4XG4PAPvGiGoVx9hFbEkLG4D8YmIO9gu2t4KUAjs6tF5wlxAAaAIphnUo-MK-Xm830k5cAg42jV4Y6BwBbjfVIXBfHZ7eI5kdLgjnUXEeBGJAxgKNUIC+Yc7jHLw-mSGQgA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
export interface NoneMetric {
  readonly unit: "None";
  readonly value: number;
}

export type DurationMetric = {
  readonly unit: "Seconds";
};

export type ErrorMetric = {
  readonly unit: "Error";

  // Below types are finite; they prevent the `unit` field from discriminating the union in the `spec` object
  readonly value: 'fatal' | 'error' | 'warning';
  // readonly value: 0 | 1;
  // readonly value: boolean;
  // readonly value: null | undefined;

  // Below types are infinitely sized; these will give you the discriminating behavior you expect
  // readonly value: string;
  // readonly value: number;
  // readonly value: any;
  // readonly value: Array<0>;
};

export type MetricEvent = NoneMetric | DurationMetric | ErrorMetric;

const spec: MetricEvent = {
  unit: "Seconds",
  value: 10, // Expected an error here since `unit` should always narrow to `DurationMetric`
};
```

### 🙁 Actual behavior

**When `ErrorMetric.value` is a finite domain type:**  
The `spec` object fully satisfies `MetricValue` (with no error) despite not satisfying any constituent members of that union. There is no error on `spec.value` being present despite `unit` being `Seconds`. 

**When `ErrorMetric.value` is an infinite domain type:**  
The `spec` object narrows to `DurationMetric. There is an error on `spec.value` indicating that `value` does not exist on `DurationMetric`.

### 🙂 Expected behavior

The `spec` object should always narrow to `DurationMetric` based on the discriminant `unit` field. The narrowing should not be impacted by the `value` field on other types since `unit` uniquely defines the discriminated union members.