microsoft / microsoft/TypeScript
Non‑`void` returning assertion functions
Open
Nobody has claimed this yet.
Awaiting More Feedback
Suggestion
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
Search Terms
- assertion function non-void return type
- assertion function non-void return
- assertion function generic return
- assertion function custom return
Suggestion
A way to type a function that is both an assertion function and returning a value that is not void.
Use Cases
This is necessary to correctly type Jest’s expect(…) matchers, which have a generic return type of R.
Examples
declare const expect: <T>(actual: T): JestMatchers<T>;
type JestMatchers<T> = JestMatchersShape<
Matchers<void, T>,
Matchers<
Promise<void>,
T extends PromiseLike<infer U>
? U
: Exclude<T, PromiseLike<any>>
>
>;
type JestMatchersShape<TNonPromise extends {} = {}, TPromise extends {} = {}> = {
resolves: AndNot<TPromise>;
rejects: AndNot<TPromise>;
} & AndNot<TNonPromise>
type AndNot<T> = T & { not: T };
interface Matchers<R, T = {}> {
toBe<E>(expected: E): R & (asserts T is E);
}
declare const foo: unknown;
expect(foo).toBe("foo");
foo; // $ExpectType "foo"
// Some typings for engine262's Completion Record handling:
type UnwrapNormalCompletion<T>
= unknown extends T ? Value | undefined
: T extends NormalCompletion<infer V>
? (unknown extends V ? Value | undefined : V)
: T extends Completion ? never
: T;
/** @see https://tc39.es/ecma262/#sec-returnifabrupt */
export declare function ReturnIfAbrupt<T>(completion: T):
(UnwrapNormalCompletion<T>)
& (asserts completion is UnwrapNormalCompletion<T>);
/** @see https://tc39.es/ecma262/#sec-returnifabrupt-shorthands */
export { ReturnIfAbrupt as Q };
/**
* The type signature is the same, but `AssertNormalCompletion` causes an error to be thrown at runtime
* if `argument` is an AbruptCompletion, whereas `ReturnIfAbrupt` gets replaced with code that causes
* the caller to return the AbruptCompletion by engine262's build system:
*
* @see https://tc39.es/ecma262/#sec-returnifabrupt
* @see https://tc39.es/ecma262/#sec-returnifabrupt-shorthands
*/
declare function AssertNormalCompletion<T>(completion: T):
(UnwrapNormalCompletion<T>)
& (asserts completion is UnwrapNormalCompletion<T>);
export { AssertNormalCompletion as X };
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No implementation files or tests are named. Start by reviewing TypeScript's existing assertion-function handling and the examples for Jest matchers and completion records. Done means supporting assertion functions with non-void generic returns while preserving the demonstrated type narrowing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100