asserttt

1.0.1 • Public • Published

asserttt: minimal API for testing types


Table of contents:


Installation

npm install asserttt

asserttt has no non-dev dependencies!

Use cases

Complementary tools

If a file contains type tests, it’s not enough to run it, we must also type-check it:

  • tsx (TypeScript Execute) is a tool that type-checks files before running them.
  • ts-expect-error performs two tasks:
    • Checking if each @ts-expect-error annotation prevents the right kind of error
    • Optional: reporting errors detected by TypeScript
  • Markcheck tests Markdown code blocks.

Usage

import { type Assert, assertType, type Assignable, type Equal, type Extends, type Includes, type Not } from 'asserttt';

//========== Asserting types: Assert<B> ==========

{
  type Pair<X> = [X, X];
  type _1 = Assert<Equal<
    Pair<'a'>, ['a', 'a']
  >>;
  type _2 = Assert<Not<Equal<
    Pair<'a'>, ['x', 'x']
  >>>;
}

{
  type _ = [
    Assert<Assignable<number, 123>>,

    Assert<Extends<Array<string>, Object>>,
    Assert<Not<Extends<Array<string>, RegExp>>>,

    Assert<Includes<'a'|'b', 'a'>>,
    Assert<Includes<'a'|'b'|'c', 'a'|'c'>>,
  ];
}

//========== Asserting types of values: assertType<T>(v)  ==========

const n = 3 + 1;
assertType<number>(n);

API

Asserting

  • Assert<B>
  • assertType<T>(value)

Included predicates (boolean results)

Equality:

  • Equal<X, Y>
  • MutuallyAssignable<X, Y>
  • PedanticEqual<X, Y>

Comparing/detecting types:

  • Extends<Sub, Super>
  • Assignable<Target, Source>
  • Includes<Superset, Subset>
  • IsAny<T>

Boolean operations:

  • Not<B>

How does the code work?

Determining if two types are equal

MutuallyAssignable

export type MutuallyAssignable<X, Y> =
  [X, Y] extends [Y, X] ? true : false
  ;
  • The brackets on the left-hand side of extends prevent distributivity.
  • Almost what we want for checking equality, but any is equal to all types – which is problematic when testing types.

Equal: like MutuallyAssignable but any is only equal to itself

This Equal predicate works well for many use cases:

type Equal<X, Y> =
  [IsAny<X>, IsAny<Y>] extends [true, true] ? true
  : [IsAny<X>, IsAny<Y>] extends [false, false] ? MutuallyAssignable<X, Y>
  : false
  ;
type IsAny<T> = 0 extends (1 & T) ? true : false;

PedanticEqual: a popular hack with several downsides

type PedanticEqual<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends // (A)
  (<T>() => T extends Y ? 1 : 2) ? true : false // (B)
  ;

It was suggested by Matt McCutchen (source). How does it work (source)?

In order to check whether the function type in line A extends the function type in line B, TypeScript has to compare the following two conditional types:

T extends X ? 1 : 2
T extends Y ? 1 : 2

Since T does not have a value, both conditional types are deferred. Assignability of two deferred conditional types is computed via the internal function isTypeIdenticalTo() and only true if:

  1. Both have the same constraint.
  2. Their “then” branches have the same type and their “else” branches have the same type.

Thanks to #1, X and Y are compared precisely.

This hack has several downsides: See test/pedantic-equal_test.ts for more information.

Asserting

type Assert<_T extends true> = void;

Alas, we can’t conditionally produce errors at the type level. That’s why we need to resort to a type parameter whose extends constraint requires it to be assignable to true.

(Idea by Blaine Bublitz)

Related work

  • Package ts-expect inspired this package. It’s very similar. This package uses different names and has a utility type Assert (which doesn’t produce runtime code):

    type _ = Assert<Equal<X,Y>>; // asserttt
    expectType<TypeEqual<X, Y>>(true); // ts-expect
  • The type-challenges repository has a module with utility types for exercises. How is asserttt different?

    • Smaller API
    • Different names
    • Implements boolean NOT via a helper type Not (vs. two versions of the same utility type).
  • eslint-plugin-expect-type supports an elegant notation but requires a special tool (eslint) for checking.

Readme

Keywords

none

Package Sidebar

Install

npm i asserttt

Weekly Downloads

165

Version

1.0.1

License

MIT

Unpacked Size

15.1 kB

Total Files

8

Last publish

Collaborators

  • rauschma