Repository: TypeScript
Issue: Suggestion: Type-check statement to verify type assignability
Labels: Suggestion,Awaiting More Feedback

## Search Terms

type check statement compile (compilation) time 

## Suggestion

I wanted to check compatibilities for types from different (especially external) modules in compilation time.

```ts
import { SomeType } from 'some-external';
// ... something statement here to check if SomeType is not changed
// by update for 'some-external' or etc.
```

To solve it, I suggest to add type-check statement like following:

```ts
// Compile error if 'SomeType' does not satisfy the constraint 'WantedType'
//   (similar to error TS2344)
type assert SomeType extends WantedType;
// The message "Unexpected 'SomeType'" will be output if the error occurs
// - The trailing expression (message clause) must be a valid string literal
// (the message clause is not necessary for this suggestion
//  but would make easier to solve the error...)
type assert SomeType extends WantedType, "Unexpected 'SomeType'";
```

* The type-check process should be same as the process for type constraints in type parameters.
* There is already `type` statement, but the above statements are not conflicted because `type` statements requires `=` after _BindingIdentifier_ (or _TypeParameters_).
* Similar to #10421, but this `type assert` only check types; it does not cast variables.
* `extends` keyword may confuse to one used in conditional type. (not ambiguous?)
  * For `type assert A extends B`, both `A` and `B` should accept conditional type.
* (`type assert` is somewhat inspired by other languages' `assert` statements (especially `static_assert` in C/C++), but I don't know whether the words `type assert` are the best...)

## Use Cases

* Check compatibilities for types simply and easily
  * Useful to avoid using incompatible package versions with another packages/modules.
* Assert types explicitly with more human-readable
  * This would not be useful for compilers/implementers, but would be useful for developers to read codes.
* Test type definition (e.g. for unit test)

Currently we can check types statically as following:

```ts
import { SomeType } from 'some-external';
// Helper definition to check type
type TypeCheckerOfWantedType<T extends WantedType> = T;
// Error if 'SomeType' does not satisfy 'WantedType'
type CheckResultForSomeType = TypeCheckerOfWantedType<SomeType>;
// this is necessary to avoid "'CheckResultForSomeType' is declared but never used"
declare global { var _dummyVariableForCheckSomeType: CheckResultForSomeType; }
```

While no JavaScript codes are generated from this code, this is more complex to check.

## Examples

```ts
// Must not be an error
type assert Element extends Node;
// Error in 'es5', pass in 'es2015'
type assert ObjectConstructor extends { assign: (...args: any[]) => any; },
  'Object.assign() is not available';

import { User } from 'db-library';
// Error if User does not have 'id' member with type assignable to 'number'
type assert User extends { id: number; }, 'Unexpected User type';

const a = someFunction();
if (typeof a === 'string') {
    // treat 'a' as 'string'
} else {
    // Error if narrowed type of 'a' does not have '{ data: string }'
    type assert typeof a extends { data: string; };
    // (this assert does not mean that type of 'a' is treated as '{ data: string }' here)
}
```

## Checklist

My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).