@maddimathon/utility-typescript
Version:
TypeScript utilities (types, functions, classes) to use in various projects.
124 lines (123 loc) • 3.71 kB
TypeScript
/**
* Utility types for unit testing TypeScript types.
*
* Types derived from and inspired by
* {@link https://github.com/MichiganTypeScript/type-testing | MichiganTypeScript/type-testing}
* (GitHub) and
* {@link https://frontendmasters.com/blog/testing-types-in-typescript/#getting-serious | *Testing Types in TypeScript*}
* by Adam Rackis.
*
* @module Test
*
* @since 0.1.0
*
* @example
* ```ts
* import { Test } from '@maddimathon/utility-typescript/types';
* ```
*
* Your type tests should probably be in the same file as your Javascript tests
* (and not in your production code where those objects are defined). For this
* example, imagine we imported this function to test.
*
* {@includeCode ./test.example.docs.ts#FunctionToTest}
*
* These values should also be tested by Jest/etc. for their values — and though
* this example is just looking at type testing, this lets us test the inferred
* return types at the same time.
*
* {@includeCode ./test.example.docs.ts#ReturnsToTest}
*
* Here’s how I would test these types. Add two types to {@link Exactly} to test
* that these types match. In rare cases you might use {@link Satisfies}.
*
* Wrap your tests in either {@link Expect} or {@link ExpectNot} — if any of
* your tests fail, this is what will cause an error.
*
* {@includeCode ./test.example.docs.ts#TypeTests}
*/
/*!
* @maddimathon/utility-typescript@2.0.0-beta.5
* @license MIT
*/
/**
* Tests if the provided arguments resolve to equivalent TypeScript values.
*
* **Does not catch all optional properties mismatches.** You should use
* {@link Exactly} instead.
*
* {@include ./test.docs.md#HowToUseTest}
*
* @param A Type to compare.
* @param B Type to compare.
*
* @since 0.1.0
*
* @internal
* @private
*/
export type Equivalent<A, B> = [
A
] extends [B] ? [B] extends [A] ? true : false : false;
/**
* Tests if two types are exactly the same shape.
*
* {@include ./test.docs.md#HowToUseTest}
*
* @param A Type to compare.
* @param B Type to compare.
*
* @since 0.1.0
*/
export type Exactly<A, B> = Equivalent<A, B> extends true ? Equivalent<Required<A>, Required<B>> extends true ? Equivalent<keyof Required<A>, keyof Required<B>> extends true ? true : false : false : false;
/**
* Demands the parameter evaluate to true.
*
* To be used with other {@link Test} types.
*
* Evaluates to true on pass and false on fail. Non-true inputs will error,
* except `never`.
*
* @param T_Test The type test to evaluate. (e.g., {@link Exactly},
* {@link IsArray}, {@link Satisfies}).
*
* @since 0.1.0
*/
export type Expect<T_Test extends true> = Exactly<T_Test, true>;
/**
* Demands the parameter evaluate to false. Inverse of {@link Expect}.
*
* To be used with other {@link Test} types.
*
* Evaluates to true on pass and false on fail. Non-false inputs will error,
* except `never`.
*
* @param T_Test The type test to evaluate (for failure). (e.g.,
* {@link Exactly}, {@link IsArray}, {@link Satisfies}).
*
* @since 0.1.0
*/
export type ExpectNot<T_Test extends false> = Exactly<T_Test, false>;
/**
* Tests if a type is a valid array.
*
* {@include ./test.docs.md#HowToUseTest}
*
* @param T_Type Type to test.
*
* @since 0.1.0
*/
export type IsArray<T_Type> = T_Type extends (infer _Item)[] ? true : false;
/**
* Tests if a given type would satisfy a given supertype.
*
* e.g., `Satisfies<"hello", string>` should evaluate to true.
*
* @param T_Type Type to compare.
* @param T_SuperType Type that should be extended by `Type`.
*
* @since 0.1.0
*/
export type Satisfies<T_Type, T_SuperType> = [
T_Type
] extends [T_SuperType] ? true : false;