Repository: TypeScript
Issue: Assertion methods (`asserts this is`) are not CFA'd without error
Labels: Bug

<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Even if you think you've found a *bug*, please read the FAQ first, especially the Common "Bugs" That Aren't Bugs section!

Please help us by doing the following steps before logging an issue:
  * Search: https://github.com/Microsoft/TypeScript/search?type=Issues
  * Read the FAQ: https://github.com/Microsoft/TypeScript/wiki/FAQ

Please fill in the *entire* template below.
-->

<!--
Please try to reproduce the issue with the latest published version. It may have already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly
-->
**TypeScript Version:**  4.0.5, 4.1.0-beta, 4.2.0-dev.20201112

<!-- Search terms you tried before logging this (so others can find this issue more easily) -->
**Search Terms:**
- Multiple assertion methods
- "asserts this is"
- assertion "cfa"

**Code**

```ts
class X<T, Locked extends boolean> {
    public x: null | T | (Locked extends true ? 1 : 2) = null

    public assert<U>(): asserts this is X<U, Locked> { }
    public lock(): asserts this is X<T, true> {}
}

const x: X<string | number, false> = new X<string | number, false>()

x.assert<string>()
// x is X<string, false> here

x.lock()
```

**Expected behavior:**

Either:
- After `x.lock()`, `x` is narrowed to `X<string, true>`
- Or, the `x.lock()` line throws at compile-time due to not being CFA'd


**Actual behavior:**

After `x.lock()`, `x` is narrowed to `X<string, false> & X<string | number, true>`.

**Playground Link:** https://www.typescriptlang.org/play?ts=4.2.0-dev.20201112#code/MYGwhgzhAEAaA8AVANNAMge2AawKYBNpcAPAF1wDt8YAjDDEXMCgPmgG8BYAKGj+gAOAVxogAlsGjEAXNApCQIaAB9oiFdAAUmHASJlK1aKQBOQ3NAD80AIzRZAJgCU0ALxyFIHj36CR4yUgIXBNSeABVFk0nWSCQ0hhSAAsxGFS4CNQdPHw2dmgAXx9+YVEJaBAsbGjYqHjElLSYBBRjM1w8ou4unmAMCghSKVkEQZMxCgBzDXkAWxoQ1AAzMBBgtncKXAB3DLGJ6dU5hZNl1fXo725iADo40Ph9qainHgB6N6lodNHTA7O1h1oEkQrgrvhcKAwCYLEshBRgKQxP0KlUkFEAG4jJCoOgMJisGLQe4JaAY77NHFtcwsK63So4S7cIA

**Analysis:**

`x` being typed as `X<string, false> & X<string | number, true>` shows that the `x.lock()` narrows from the original type (`X<string | number, false>`) instead of the narrowed type at that position (`X<string, false>`).

If instead a "top-level" assertion function is used the type is properly narrowed:

```ts
class X<T, Locked extends boolean> {
    public x: null | T | (Locked extends true ? 1 : 2) = null

    public assert<U>(): asserts this is X<U, Locked> { }
    public lock(): asserts this is X<T, true> {}
}

const x: X<string | number, false> = new X<string | number, false>()

x.assert<string>()
// x is X<string, false> here

declare function lock<T>(v: X<T, boolean>): asserts v is X<T, true>
lock(x)
```
[Playground](https://www.typescriptlang.org/play?ts=4.2.0-dev.20201112#code/LAKAxgNghgzjAEANAPAFQDTwDIHswGsBTAE3kIA8AXQgO2IQCMccJCoaA+eAb1Hn-gAHAK4MIASzDxyALng1hECPAA+8VKvgAKXARJkqtevEoAnYYXgB+eAEZ4cgEwBKeAF55iiKD4CRYyXhYGEJTSmQAVQ4tZzlg0MoESgALcQQ0pEjMXSJiLm54AF9ffn8JKQg8fBi4uASk1PSEFAwTc0J84pAu0DAcGhhKaTkUQdNxGgBzTQUAWwZQzAAzKAgQrg8aQgB3TLGJ6bU5hdNl1fWYnxByADp4sOR9qejnUAB6N+l4DNGzA7O1h14MlQoQrsRCJAoKZLEthDQwJRxP14JUCGhogA3EZoTBMFhsTixIJ1MIITHfZq4toWDigNHVcjOIA)

This leads me to believe this is an issue with the `x.lock()` call not being CFA'd, in which case the correct behavior would be to throw `ts(2775)` on the `x.lock()` line.