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:

code
// 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:

code
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:

code
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:

code
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.

code
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:

code
{
  "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:

code
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()

code
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:

code
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

If you found this interesting, check out my free FE testing newsletter

If you found this blog post useful or you learned something, you might like my free newsletter, keeping you up to date with frontend testing.

I cover topics like testing frontend apps, how to write Vitest (including the new Vitest Browser Mode), high quality tests, e2e tests and more - with actionable tips and tricks to make sure your tests are as high quality as they can be!

I only send it every couple of weeks, never spam, and you can of course unsubscribe at any time.

Want to become a pro at testing your React apps?

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