Repository: TypeScript
Issue: (Almost) arbitrary functions are assignable to an assertion-function-typed variable
Labels: Suggestion,Awaiting More Feedback

# 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.
-->

assertion functions assignability inconsistent type guards

### 🕗 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, and I reviewed the FAQ for entries about type system behavior

### ⏯ 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.6.4#code/MYewdgzgLgBAhhCBTATlAcgVwLYCNUwC8MAFAB4BcMmYA1mCAO5gCUVCyaEMZMAltzA58KIgD4YAbwBQMfgDNSUAJ4AHJCEW8AhIWIByIXlT6WU2XJhQAFiiYwAoijsoSAIgaw4MIyLcsLAF9pYIB6UJgITAhVPmA+EGj4RD4AczBsJDAoADo86VBIL0RUKABlKBQ+MFSqcioaeiZWcWTOKG5eAUjK6tSiNtKsYxRpAvBoHga6BmYBgEYABkWAbmkOUoqqmvIWFZhwmAAhJGA4aKQYAAMNtC2+q-5uOGAoTDgAGw-la9uMYVQVwAND4QDBUC4nlZbM1pKEAFSInj6bgqdRQ2Y9bb9RHw0LSMg5KK4aDYkjzPYHCIMGCgbCxD6XCEgFAg3CYWAoGhQPiZcHOFnaMbjIoweQgMHEepYvowAA+1DAABMkPJqkglWwfADRIQJEtFnCIlEYnEEkkOGkMllcvlCpM-gAVLk2ZR1SgymryxUqtVgDVmPWDLg8AbikBje2wN2e-oKmi+9VKsOfZAwAD8MH0cH0MGmif9SrWTpd1mUJGUe2kyiJmBJvR2FP2hxpdIZTIFrJg7M53N5HZcQrGCJg6BAUCQVHw1jgADcEihuJorGpLql3igldw8UaYI7VzBl1cBABVGbNR7YOBQYDWJDcNyq+SnHmzpBuFfoo+n8-MABMwIwLuPbwMAwAcu8Xw-MeEBnk0zCPN0nhtFacC4IyVhgjBcGzGAAHdqc5xpjYlwQKhbwoJc36wb+YCIYI47wJ+lyqJRSpxNeSA5CKkw-vBYADNKjS4VquASoycACUGMhyJRFECZUmBICEPGwHxuF-u60z8YGEhdNwwnNAM6mwru+7ouucCbs8lG0iAs5WXwkmwIwfA2DAlExC+mEwG4nmYB8sBou+pB8DkXHXKSDz8AJJB5Dkumht0UU1Cw3FRk8ACCLJHIJHqGcwWr6VmObevouC5tJFhyZgKACbwegGKVcoKg1ehZhVKmqU89w1Fpio6a0xUpf0xACNlKBHN1439QVLRBsV2aVVlOXSEAA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
const assertNumber = (x: unknown): asserts x is number => {
  if (typeof x !== 'number') {
    throw Error("not a number")
  }
}
// suspicious assignment...
const assertString: (x: unknown) => asserts x is string = assertNumber

const x: unknown = 100;
assertString(x); // Because `assertString` is actually `assertNumber`, no error is thrown
/*** x's type is now string ***/
x.substring(1); // no compile error, but runtime error!


const foo = (x: string | undefined): number => 100
// suspicious assignment...
const assertTruthy: (x: string | undefined) => asserts x = foo

const y: string | undefined = false ? 'a' : undefined;
assertTruthy(y);
y.substring(1); // no compile error, but runtime error!
```

### 🙁 Actual behavior

<!-- What happened, and why it was wrong -->

Both (suspicious) assignments succeed with no compile error.  This behavior is not consistent with that of type guards.

### 🙂 Expected behavior

<!-- What you expected to happen instead, and why -->

Both assignments should be rejected by the compiler.

I believe assignability rule for assertion functions should be consistent with the rule for type guards.  At least, an assignment of a function which doesn't have assertion function signature to an assertion-function-typed variable should be rejected.  Furthermore, for assertion function signatures with "result type" (`(x: ...) => asserts x is T`), it should be covariant with respect to the "result type".