Skip to content

Instantly share code, notes, and snippets.

@zachhardesty7
Last active February 12, 2024 22:01
Show Gist options
  • Save zachhardesty7/1b5b6f6de328f1bb7c78cbe96ba5c720 to your computer and use it in GitHub Desktop.
Save zachhardesty7/1b5b6f6de328f1bb7c78cbe96ba5c720 to your computer and use it in GitHub Desktop.
TS `Expect` type testing helper
// copyright 2024 Zach Hardesty
// want to check this out in the TypeScript playground?
// visit the following link to automatically see the latest version!
// https://www.typescriptlang.org/play?jsx=0#gist/1b5b6f6de328f1bb7c78cbe96ba5c720
/**
* Passes thru successful test input, errors with inputs that are not equal. nice when
* you have a bunch of `never`s. can handle checking if things are `any` or `unknown` too.
*
* Can be used in the middle of an expression and composed to check each step
*
* **NOTE:** when both or neither of input/expected are `any`, checks they extend each
* other, otherwise only 1 is `any` and this manually shows an error message (instead of
* `never` for readability) since `any` is a supertype of everything and input would
* always match expected
*
* @example
* // no errors here, `TypeTest1` silently becomes `never`
* type TypeTest1 = false extends true ? { a: string } : never
* // TS shows an error here and `TypeTest2` still becomes `never`
* type TypeTest2 = Expect<
* false extends true ? { a: string } : never,
* { a: string }
* >
* // passing test, but `TypeTest3` also becomes the result of simplifying the input ({ a: string })
* type TypeTest3 = Expect<true extends true ? { a: string } : never, { a: string }>
*
* @todo Check for perf issues with recursion
* @see https://github.com/sindresorhus/type-fest/blob/main/source/is-any.d.ts
*/
type Expect<
TInput extends TCheck,
TExpected extends TCheck,
TCheck = IsAny<TInput> extends IsAny<TExpected>
? TInput extends TExpected
? TInput
: TExpected
: "exactly `any` type",
> = TInput;
/** @see https://github.com/sindresorhus/type-fest/blob/main/source/is-any.d.ts */
type IsAny<T> = 0 extends 1 & T ? true : false;
/** incorrectly allows any type when checking for exactly `any` */
type BasicExpect<
TInput extends TIntersect,
TExpected extends TIntersect,
TIntersect = TExpected & TInput,
> = TInput;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment