Expect API
TSTyche ships expect style assertions to check types.
TSTyche uses TypeScript API to infer types of expressions. For an overview of the aspects of TypeScript type inference that commonly affect type tests, see the Type Inference page.
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 other expressions.
Signatures. The source type must be provided either as a type argument or inferred from an expression.
expect<S>()
expect(source: unknown)Run Mode Flags
To focus or skip assertions, append the run mode flags to the expect() function. The flags are inherited from the parent.
.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 type errors inside the skipped assertion.
Use the // @tstyche fixme comment directive to mark any expect() as failing. To learn more, see the Comment Directives page.
Matchers
A matcher is the final element in the assertion chain. It defines the condition to check.
.not
To negate a matcher, prepend .not before it:
import { expect } from "tstyche";
expect<string>().type.toBe<string>();
expect<number>().type.not.toBe<string>();.toAcceptProps()
Checks if the JSX component accepts the given props.
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 });
()...({});
});Signature. The props must be provided as an object literal.
.toAcceptProps(props: Record<string, unknown>).toBe()
Checks if the source type is the same as the target type.
import { } from "tstyche";
type <> = {
[ in keyof ]+?: [] | <[]>;
};
type <> = & { : boolean };
<<<{ : string }>>>()..<{
?: string | <string>;
: boolean;
}>();The types are compared structurally. As shown in the example above, the matcher treats { a: string } & { b: number } and { a: string; b: number } as equivalent.
The matcher allows granular checks of every detail. For example, it distinguishes between types with and without the NoInfer marker:
import { } from "tstyche";
const = <>(: ) => ;
const = <>(: <>) => ;
(("kiwi"))..<"kiwi">();
(("kiwi"))..<unknown>();
// Identical input results in a different return type,
// therefore the matcher treats these signatures as non-equivalent
()...();Signatures. The target type must be provided either as a type argument or inferred from an expression.
.toBe<T>()
.toBe(target: unknown).toBeApplicable
Checks if the decorator function can be applied to a class or a class member.
Unlike other matchers, .toBeApplicable must be used as a decorator:
import { , } from "tstyche";
function <, extends (: , ...: any) => any>(
: ,
: <, >,
) {
// ...
}
("bind", () => {
class {
#name: string;
constructor(: string) {
this.#name = ;
}
@(()..) // <-- used as a decorator here
() {
return `Hello, my name is ${this.#name}.`;
}
}
});.toBeAssignableFrom()
Checks if the source type is assignable from the target type.
import { , } from "tstyche";
type <> = | <>;
("Awaitable", () => {
<<string>>()..("abc");
<<string>>()..(.("abc"));
<<string>>()...(123);
<<string>>()...(.(123));
});Use the .toBeAssignableTo() matcher to test the relationship in the reverse direction.
As a best practice, always keep the type under test on the left hand side of the assertion. This makes the test easier to read:
- expect<Set<string>>.type.toBeAssignableFrom(new Set(["abc"]));
+ expect(new Set(["abc"])).type.toBeAssignableTo<Set<string>>();Signatures. The target type must be provided either as a type argument or inferred from an expression.
.toBeAssignableFrom<T>()
.toBeAssignableFrom(target: unknown).toBeAssignableTo()
Checks if the source type is assignable to the target type.
import { , } from "tstyche";
("Set", () => {
(new (["abc"]))..<<string>>();
(new ([123]))..<<number>>();
(new ([123, "abc"]))...<<string>>();
(new ([123, "abc"]))...<<number>>();
});Use the .toBeAssignableFrom() matcher to test the relationship in the reverse direction.
As a best practice, always keep the type under test on the left hand side of the assertion. This makes the test easier to read:
- expect("abc").type.toBeAssignableTo<Awaitable<string>>();
+ expect<Awaitable<string>>().type.toBeAssignableFrom("abc");Signatures. The target type must be provided either as a type argument or inferred from an expression.
.toBeAssignableTo<T>()
.toBeAssignableTo(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 matcher accepts zero or more arguments.
.toBeCallableWith(...args: 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 matcher accepts zero or more arguments.
.toBeConstructableWith(...args: Array<unknown>).toBeInstantiableWith()
Checks if a generic is instantiable with the given type arguments.
import { type , } from "tstyche";
interface <, = unknown> {
[: string]: (: ) => ;
}
<<>>()..<[void]>();
<<>>()..<[void, string]>();
<<>>()...<[]>();The _ type can be used to fill in the required type arguments.
This matcher works with generic interfaces, type aliases, classes and functions:
import { } from "tstyche";
function <, >(: <>, : (: ) => ): <> {
return .();
}
()..<[string, number]>();
()...<[string]>();Signature. The type arguments must be provided as a tuple type.
.toBeInstantiableWith<T extends [...args: 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 must be a string, number or symbol.
.toHaveProperty(key: string | number | symbol).toRaiseError()
Checks if the type raises an error.
The .toRaiseError() matcher is deprecated and planned to be removed. The suggested replacement is the ability matchers (like .toBeCallableWith() or .toBeConstructableWith()). They communicate the intent of a test more clearly and work without introducing type errors in the test code.
To learn more, see the Expect Errors page.