Skip to Content
ReferenceExpect API

Expect API

TSTyche includes the expect flavoured assertions to compare types.

Type Inference Caveats

If an expression is passed as the target or the source of an assertion, TSTyche will use the TypeScript’s type checker to infer its type. This section is a reminder of some aspects of the inference process (like type widening or excess property checks) that may be misinterpreted.

TSTyche sees exactly the same types which you see in code editor’s hover messages. To learn more, see the Introduction page.

Type Widening

In mutable context a literal type is inferred  as its base type:

import { } from "tstyche"; const = { : 2, : [3, 3] }; ()..<{ : number; : number[] }>();

To tell to the type checker that a type should not be widened, use type assertions :

import { } from "tstyche"; const = { : 6 as , : [9, 9] as 9[] }; ()..<{ : 6; : 9[] }>();

It is also possible to use the const type assertion to convert the entire object, but in this case a different type is created:

import { } from "tstyche"; const = { : 6, : [9, 9] } as ; ()..<{ readonly : 6; readonly : readonly [9, 9] }>();

Excess Property Checks

If passed as arguments, the object literals undergo the excess property checks :

import { } from "tstyche"; let : { ?: number } = {}; = { silent: true, : 800 };
Object literal may only specify known properties, and 'silent' does not exist in type '{ timeout?: number | undefined; }'.
// Just like above, object literals may only specify known properties ({ : true, : 800 })...<{ ?: number }>(); <{ ?: number }>()...({ : true, : 800 }); // But object types are allowed to have excess properties <{ : true; : 800 }>()..<{ ?: number }>(); <{ ?: number }>()..<{ : true; : 800 }>();

Generally these failures prevent outdated assertions hanging around in your tests. If the excess property checks is not what you need, follow the above link to learn how to get around them. For example, you can pass a reference instead of an object literal:

import { } from "tstyche"; const = { : true, : 800 }; ()..<{ ?: number }>(); <{ ?: number }>()..();

expect()

The expect() function builds an assertion. It must be followed by the .type modifier and a matcher. Optionally a run mode flag can be appended. expect() can be nested inside code.


Signatures. The source type can be passed as a type argument or inferred from an expression:

expect<Source>() expect(source: unknown)

Run Mode Flags

To select assertions to run, append the run mode flags to the expect() function. The flags are inherited from the parent.

.fail

Marks an assertion as supposed to fail. The test runner will make sure that the assertion actually fails. If it is passing, an error will be raised.

Use .only.fail to focus on or .skip.fail to skip a supposed to fail assertion.

.only

Marks an assertion as focused. When there are focused groups, tests or assertions in a file, only those will run.

.skip

Marks an assertion as skipped. The test runner will ignore anything skipped and will suppress any type errors raised by the expressions or types passed to the expect() or a matcher function.

Type Utilities

TypeScript ships utility types like Omit or Pick that reshape types. They can also be useful when testing types. If you are testing types of expressions, use the omit() or pick() type utilities to have same results.

The utilities only reshape types. At runtime they return the same object that was passed as an argument.

omit()

The omit() type utility reshapes type of the given object by removing the specified keys:

import { , , } from "tstyche"; class <> { : <> = []; get (): number { return this..; } (: ): void { this..(); } } ((new (), "enqueue", "entries"))..<{ readonly : number; }>(); // Equivalent to the 'Omit' utility type <<<string>, "enqueue" | "entries">>()..<{ readonly : number; }>();

pick()

The pick() type utility reshapes type of the given object by keeping only the specified keys:

import { , , } from "tstyche"; class <> { : <> = []; get (): number { return this..; } (: ): void { this..(); } } ((new (), "size"))..<{ readonly : number }>(); // Equivalent to the 'Pick' utility type <<<string>, "size">>()..<{ readonly : number }>();

Matchers

A matcher is the last element of the assertion chain. It holds an assumption to check.

.not

To negate the condition, prepend .not before any matcher:

import { expect } from "tstyche"; expect<string>().type.toBe<string>(); expect<number>().type.not.toBe<string>();

.toAcceptProps()

Checks if the JSX component accepts props of the given type.

This is a work in progress feature. Generic components are not yet supported.

import { , } from "tstyche"; interface ButtonProps { : string; ?: "reset" | "submit"; } function ({ , }: ButtonProps) { return < ={}>{}</>; } ("accepts props?", () => { ()..({ : "Send" }); ()..({ : "Clear", : "reset" as }); ()...({ : "Download", : "button" as }); ()...({}); });

Signatures. The props type can be passed as a type argument or inferred from an expression:

.toAcceptProps<Target>() .toAcceptProps(target: unknown)

.toBe()

Checks if the source type the same as the target type.

import { , } from "tstyche"; type = (...: any) => any; type <> = keyof { [ in keyof as <>[] extends ? : never]: []; }; interface Sample { : string; : () => number; ?: () => number; } ("MethodLikeKeys", () => { <<Sample>>()..<"getLength" | "getWidth">(); });

Signatures. The target type can be passed as a type argument or inferred from an expression:

.toBe<Target>() .toBe(target: unknown)

.toBeApplicable

Checks if the decorator function can be applied to a class or a class member.

Differently from other matchers, .toBeApplicable must be used as a decorator:

import { , } from "tstyche"; function <, extends (: , ...: any) => any>( : , : <, >, ) { // ... } ("bind", () => { class { #name: string; constructor(: string) { this.#name = ; } @(()..) // <-- and here it is! () { return `Hello, my name is ${this.#name}.`; } } });

.toBeAssignableTo()

Checks if the source type is assignable to the target type. The opposite of the .toBeAssignableWith() matcher.

import { , } from "tstyche"; ("Set", () => { (new (["abc"]))..<<string>>(); (new ([123]))..<<number>>(); (new ([123, "abc"]))...<<string>>(); (new ([123, "abc"]))...<<number>>(); });

Signatures. The target type can be passed as a type argument or inferred from an expression:

.toBeAssignableTo<Target>() .toBeAssignableTo(target: unknown)

.toBeAssignableWith()

Checks if the source type is assignable with the target type. The opposite of the .toBeAssignableTo() matcher.

import { , } from "tstyche"; type <> = | <>; ("Awaitable", () => { <<string>>()..("abc"); <<string>>()..(.("abc")); <<string>>()...(123); <<string>>()...(.(123)); });

Signatures. The target type can be passed as a type argument or inferred from an expression:

.toBeAssignableWith<Target>() .toBeAssignableWith(target: unknown)

.toBeCallableWith()

Checks if a function is callable with the given arguments.

import { , } from "tstyche"; function < extends { : number }>(: , : ) { return . === .; } ("isSameLength", () => { (([1, 2], [1, 2, 3]))..<boolean>(); (("one", "two"))..<boolean>(); ()...(1, 2); ()...("zero", [123]); (<string | <number>>)..("zero", [123]); });

Signature. The target should list zero or more given arguments:

.toBeCallableWith(...target: Array<unknown>)

.toBeConstructableWith()

Checks if a class is constructable with the given arguments.

import { , } from "tstyche"; class <> { : ; : ; constructor(: , : ) { this. = ; this. = ; } } ("Pair", () => { ()..("sun", "moon"); ()..(true, false); ()...("five", 10); (<number | string>)..("five", 10); ()...(); ()...("nope"); });

Signature. The target should list zero or more given arguments:

.toBeConstructableWith(...target: Array<unknown>)

.toHaveProperty()

Checks if a property key exists on the source type.

import { , } from "tstyche"; type <> = { [ in keyof as <, "setup" | "teardown">]: []; }; interface Sample { [: `data-${string}`]: string; ?: boolean | undefined; : (: string, : number) => void; : () => void; : () => void; } ("Worker", () => { <<Sample>>()..("data-sample"); <<Sample>>()..("isBusy"); <<Sample>>()..("runTest"); <<Sample>>()...("setup"); <<Sample>>()...("teardown"); });

Signature. The key argument can be passed as a string, number or symbol:

.toHaveProperty(key: string | number | symbol)

.toRaiseError()

Checks if the source type raises an error.

import { , } from "tstyche"; interface <, = unknown> { [: string]: (: ) => ; } ("Matchers", () => { <<void, string>>()...(); <<void>>()...(); <>()..("requires between 1 and 2 type arguments"); });

It is recommended to pass a substring of an error message to the matcher. Alternatively a numeric error code can be provided. If the source type raises several errors, the matcher will require an argument for each of them.

Avoid the // @ts-expect-error comments in your type tests, instead always use .toRaiseError(). The comment suppresses syntax errors, hence it turns typos into falsy passing tests. For example, the following is passing despite two syntax errors:

interface <, = unknown> { [: string]: (: ) => ; } // @ts-expect-error: requires a type argument type = <>;

Signature. The target argument is optional. It can be one or more substrings, numeric codes or regular expressions:

.toRaiseError(...target: Array<string | number | RegExp>)
Last updated on