Repository: TypeScript
Issue: [TS 4.2] Narrowing a union type is inconsistent using type guards on different member of union
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.
-->
narrowing union type

### 🕗 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

### ⏯ 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](gzwGEIATVAXjgCYAGZuAHyeYEYBYAKFCRYCZKgBixAJYAbDFGBFS5KrTgMALKw5wt3HVsYHmAZh0BWbZ0uMBAqQDsYwKADNiuOAAkYMMACV8SAc8YAAeJTJKGlRQZwdqPHRsXAJIlRidSVl5RRIo1WAAPjgAbwE4ODx8jNoALnQa6NoBAF87fkdnNw9UABlgAHMPRABBMClAvGDQuDjgBKSABWJYKWIZMNK4AG0Aa2BEBuqoR0GAXQaMBz2HCAB3BzhWkvL+AEhq5WbgAH4GhzAABuLjaHSQKGSOHwSQYPj8Uxm4Uw0LSTUKJU4A2GWDGE0REBCwAEEIk0jkCnU3l8ASChNCYWyFLy3wx4LEcCmGBkMAicxA8USUNSeAANHBxPzBUkmbkqYCQVASgw0FkOrQsDJVqhXNcsDApIS4Ao8NyYABJQgpGF8+aLYUw8WSu1C2UKIoACigDS5PIiTqKAEoGlA4FIkmgBBqtZTdQ59YaniazZa3cipQshSiRU6M-a057vZz8Gb-RKgyGwzL2ZCACr4GC++AMJtbKrWggNGBQDCoVri+G06b08JaExFIrq4Ca7VwLD0+DJnkNevVJsdITQeBxhNG5zVD2BsoVMOuOBeks81Pk3IX008wNHt6VSpL+AAenfcHNDlcLgU1BwMQSSDgSRJhGORQAHQnq0cwyLMz4vm+cCft+v7-sAgHAWU7aongXY9n2MH8JU7T8ORAibiIO4GnuDaMIex6kae55vpa2YwneZqPsxL7GpeH5fj+f5QABQFJNspr4YRvbPCRZHwYhJ6voJqFfhQxAOHc8COKJ4pfIgElwKujaCQpzxgvwQA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
export type SuccessStatusCode = 200 | 201
export type FailureStatusCode = 400 | 401 | 402 | 403 | 500 | 502

interface HttpResponse<StatusCode extends SuccessStatusCode | FailureStatusCode> {
  statusCode: StatusCode
}

interface LegacyApiResponse extends Partial<{ [key: string]: unknown }> {
	statusCode?: never
}

type Success = HttpResponse<SuccessStatusCode> | LegacyApiResponse
type Failure = HttpResponse<FailureStatusCode>

type Result<S extends Success, F extends Failure = never> = S | F

declare function resultIsSuccess<S extends Success, F extends Failure>(r: Result<S, F>): r is S
declare function resultIsFailure<S extends Success, F extends Failure>(r: Result<S, F>): r is F

type TestResult = Result<{ success: true }, HttpResponse<403>>

declare const result: TestResult

export function test() {
  if (resultIsFailure(result)) {
    result // Inferred as HttpResponse<403>.
  } else {
    result // Inferred as { success: true }.
  }
}

export function test2() {
  if (resultIsSuccess(result)) {
    result // Inferred as { success: true }.
  } else {
    result // Cannot infer, stay as TestResult.
  }
}
```

### 🙁 Actual behavior

While `test1` works fine, in `test2`, the else branch cannot narrow the type to `HttpResponse<403>`.

### 🙂 Expected behavior

`test1` and `test2` are just narrowing down `result` using complementary type guards, their behavior should be consistent.
And they are consistent in 4.1.