Jestype is a TypeScript utility designed to facilitate type testing within Jest, providing developers with tools to assert and validate type behaviors in TypeScript projects. At its core, expectType
serves as the type-level counterpart to Jest's expect
function, enabling type assertions in a manner analogous to value-based testing.
Install Jestype in your development environment with npm:
npm install jestype --save-dev
Then, import and use expectType
in your Jest tests to validate types.
expectType
is the primary function of Jestype and acts as the type-level equivalent of Jest's expect
.
It allows type assertions for a specific type T
, providing a fluent API for asserting type properties and relationships.
import { expectType } from 'jestype';
// Assert that a type is exactly another type
expectType<string>().toBe<string>();
// Assert that a type extends another type
expectType<string>().toExtend<string | number>();
// Negation example
expectType<string>().not.toBe<number>();
-
.toBe<S>()
: Asserts that the tested typeT
is exactly the same as typeS
. -
.toExtend<S>()
: Asserts that the tested typeT
extends typeS
. -
.toBeOfUnion<S>()
: Asserts that the tested typeT
is part of the unionS
-
.toHave<S>()
: Asserts that the tested typeT
has the same properties as typeS
. -
.toBePartOf<S>()
: Asserts that the tested typeT
is a subset of typeS
. -
.toHaveRequired<K extends string[]>()
: Asserts that the tested typeT
has all the required keys specified inK
. -
.toHaveOptional<K extends string[]>()
: Asserts that the tested typeT
has all the optional keys specified inK
. -
.not
: Inverts the subsequent type assertion, allowing for negated checks.
Asserts that the tested type T
is exactly the same as type S
.
// Should pass: string is exactly a string
expectType<string>().toBe<string>();
// Should fail: string is not a number
expectType<string>().toBe<number>();
Asserts that the tested type T
extends type S
.
/* Using Interfaces*/
interface Base {
baseProp: string;
}
interface Extended extends Base {
extendedProp: number;
}
// Should pass: Extended extends Base
expectType<Extended>().toExtend<Base>();
// Should fail: Base does not extend Extended
expectType<Base>().toExtend<Extended>();
/* Using Unions */
// Should pass: string is assignable to string | number
expectType<string>().toExtend<string | number>();
// Should fail: string | number is not assignable to string
expectType<string | number>().toExtend<string>();
Asserts that the tested type T
is part of the union S
Exactly the same as toExtend
, but lends to a more intuitive sounding type assertion for unions
// Should pass: `string` is part of union `string | number`
expectType<string>().toBeOfUnion<string | number>();
// Should fail: `string` is not in union `string | number`
expectType<string | number>().toBeOfUnion<string>();
Asserts that the tested type T
has the same properties as type S
.
interface Person {
name: string;
age: number;
}
// Should pass: Person has name and age properties
expectType<Person>().toHave<{ name: string; age: number; }>();
// Should fail: Person does not have a salary property
expectType<Person>().toHave<{ salary: number; }>();
Asserts that the tested type T
is a subset of type S
.
interface Vehicle {
make: string;
model: string;
year: number;
}
interface Car {
make: string;
model: string;
}
// Should pass: Car is part of Vehicle
expectType<Car>().toBePartOf<Vehicle>();
// Should fail: Vehicle is not a subset of Car
expectType<Vehicle>().toBePartOf<Car>();
Asserts that the tested type T
has all the required keys specified in K
.
interface User {
id: number;
name: string;
email?: string;
}
// Should pass: User has required keys id and name
expectType<User>().toHaveRequired<['id', 'name']>();
// Should fail: User does not have a required key 'password'
expectType<User>().toHaveRequired<['password']>();
Asserts that the tested type T
has all the optional keys specified in K
.
interface Product {
id: number;
name: string;
description?: string;
price?: number;
}
// Should pass: Product has optional key 'description'
expectType<Product>().toHaveOptional<['description']>();
// Should fail: Product does not have an optional key 'weight'
expectType<Product>().toHaveOptional<['weight']>();
Inverts the subsequent type assertion, allowing for negated checks.
// Should pass: string is not a number
expectType<string>().not.toBe<number>();
// Should fail: string is not a number
expectType<string>().<number>();
Jestype also includes Utility Types that expectType is built on:
-
And<T, U>
: Logical AND ofT
andU
. -
Or<T, U>
: Logical OR ofT
andU
. -
Not<T>
: Logical NOT ofT
. -
Nand<T, U>
: Logical NAND ofT
andU
. -
Nor<T, U>
: Logical NOR ofT
andU
. -
Xor<T, U>
: Logical XOR ofT
andU
. -
Eq<T, U>
: Checks ifT
andU
are equivalent. -
All<Items>
: True if allItems
are true. -
Any<Items>
: True if any ofItems
are true. -
None<Items>
: True if none ofItems
are true. -
Switch<Condition, Inverted>
: EvaluatesCondition
and inverts the result ifInverted
istrue
. -
If<Condition, Then, Else>
: ReturnsThen
ifCondition
istrue
, otherwiseElse
.
-
Extends<T, S>
: Determines if typeT
extends typeS
. -
BiExtends<T, S>
: Determines if typesT
andS
are mutually extendable (bi-directional extends).
-
RequiredKeys<T>
: Extracts the required keys of typeT
. -
OptionalKeys<T>
: Extracts the optional keys of typeT
. -
AlwaysKeys<T>
: Extracts keys ofT
that are always present.
-
IsAny<T>
: Determines if typeT
isany
. -
IsNever<T>
: Determines if typeT
isnever
. -
IsUnknown<T>
: Determines if typeT
isunknown
. -
IsEmpty<T>
: Determines if typeT
is an empty object ({}
). -
IsPrimitive<T>
: Determines if typeT
is a primitive type.
Brand<T>
: Creates a branded representation of typeT
, useful for complex type analysis.