How to add type check assertions in Vitest

September 21, 2025
#testing#vitest#typescript#frontend

Sometimes it can be really important that you are able to test your types. For example, if you are publishing a package you might want to ensure the types that you publish match types used elsewhere in your system.

This is really easy with Vitest!

What is meant by type check tests?

So if you have a Typescript app, you probably have a step in your CI/CD which checks that all the types in your app match.

If you had this for example, it would fail:

// the :string tells typescript this will return a string...
function doesntReturnAString(): string {
  return 1; // << not a string!
}

I think most apps nowadays have these sorts of checks already.

But sometimes you might be writing complex types or functions that return a mix of generic types, and you want to assert that these are working correctly.

For example you might assert that some public API on a service's getUser() has the correct parameter types and return type:

test('API backward compatibility', () => {
  expectTypeOf<UserService['getUser']>()
    .parameter(0)
    .toEqualTypeOf<{
      id: string;
      includeDeleted?: boolean;
    }>();

  expectTypeOf<
    UserService['getUser']
  >().returns.toEqualTypeOf<
    Promise<User | null>
  >();
});

Or even test your complex generics:

type ExtractParams<T> = T extends (
  ...args: infer P
) => any
  ? P
  : never;

test('generic ExtractParams return expected types', () => {
  type TestFn = (
    a: string,
    b: number,
    c: boolean
  ) => void;

  expectTypeOf<
    ExtractParams<TestFn>
  >().toEqualTypeOf<
    [string, number, boolean]
  >();
  expectTypeOf<
    ExtractParams<string>
  >().toEqualTypeOf<never>();
  expectTypeOf<
    ExtractParams<() => void>
  >().toEqualTypeOf<[]>();
});

How to start using Vitest type checks:

Under the hood, it uses the expect-type package. Getting it working in Vitest is easy though:

Step 1: Create a new file, called something.test-d.ts

For type checks in Vitest, by default it has to have the .test-d.ts suffix .

Step 2: Then import the helper functions:

import {
  assertType,
  expectTypeOf,
} from 'vitest';

Step 3: Write your assertions

The type assertions are done via TSC, so you can use a mix of the vitest functions, along with generics.

import {
  expect,
  expectTypeOf,
  test,
} from 'vitest';

function returnAny() {
  return 'abc' as any;
}

const blogPost = {
  title: 'some blog post',
  tags: ['tag1', 'tag2'],
  body: 'here is the blog post',
};

test('type checks', () => {
  // both are number, so they're equal types
  expectTypeOf(1).toEqualTypeOf(2);

  expectTypeOf('asd').toBeString();

  expectTypeOf([]).toBeArray();

  expectTypeOf(returnAny()).toBeAny();

  expectTypeOf(blogPost).toEqualTypeOf<{
    title: string;
    tags: string[];
    body: string;
  }>();

  expectTypeOf('some string').toExtend<
    string | number
  >();

  expectTypeOf({
    a: 1,
    b: 2,
  }).toExtend<{ a: number }>();
});

Step 4: run type checks in vitest

You have to add the --typecheck flag when running vitest:

{
  "scripts": {
    "test": "vitest",
    "test:types": "vitest --typecheck --run"
  }
}

Then you can run npm run test:types, yarn test:types or pnpm test:types

Note: you can also set "test": "vitest --typecheck" to do 'normal' tests and type check tests together, when you run npm run test.

Examples

Simple assertions

Use the assertType() function - pass in the value, and the expected type as a generic:

import { assertType } from 'vitest';

test('some simple tests', () => {
  const someNumber = 123;
  assertType<number>(someNumber);

  const greeting = 'Hello';
  assertType<string>(greeting);
});

Use expectTypeOf for similar fluent syntax like expect()

import {
  expectTypeOf,
  test,
} from 'vitest';

test('expectTypeOf examples', () => {
  const user = {
    id: '123',
    name: 'Bart Simpson',
    email: 'helllo@example.com',
    age: 50,
  };

  expectTypeOf(user).toEqualTypeOf<{
    id: string;
    name: string;
    email: string;
    age: number;
  }>();

  expectTypeOf(user).toExtend<{
    id: string;
  }>();

  expectTypeOf(user.name).toBeString();
  expectTypeOf(user.age).toBeNumber();
  expectTypeOf([
    'a',
    'b',
    'c',
  ]).toBeArray();
});

Checking for type errors

Sometimes you might want to assert that a type is not valid:

const someNumber = 99;

// @ts-expect-error someNumber is not a string
assertType<string>(someNumber);

Tips

  • You cannot use test.each() to iterate over test cases.
  • You can nest the tests in describe() blocks just like regular tests
  • Remember to test the negative case. All of your tests could pass if somewhere along the way any was set as a type - so make sure to check something is failing type checks (with @ts-expect-error).
  • Read through expect-type to understand this powerful feature

Have a play

Here is the official playground to interact and try out Vitest type check tests. View it here

Found this useful? Share this article

TwitterLinkedIn Facebook

Want to become a pro at testing your React apps?

I've got a huge range of interactive lessons from beginner to expert level.

Get better at testing every week:

Join developers, engineers and testers who receive my free newsletter with React testing tips

I've been writing tests for years, but as I research content for this blog, I am always discovering new things in the tools we use every day!

Get free React/testing tips 👇