--- title: Testing Types | Guide --- # Testing Types ::: tip Sample Project [GitHub](https://github.com/vitest-dev/vitest/tree/main/examples/typecheck) - [Play Online](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/typecheck?initialPath=__vitest__/) ::: Vitest allows you to write tests for your types, using `expectTypeOf` or `assertType` syntaxes. By default all tests inside `*.test-d.ts` files are considered type tests, but you can change it with [`typecheck.include`](/config/#typecheck-include) config option. Under the hood Vitest calls `tsc` or `vue-tsc`, depending on your config, and parses results. Vitest will also print out type errors in your source code, if it finds any. You can disable it with [`typecheck.ignoreSourceErrors`](/config/#typecheck-ignoresourceerrors) config option. Keep in mind that Vitest doesn't run these files, they are only statically analyzed by the compiler. Meaning, that if you use a dynamic name or `test.each` or `test.for`, the test name will not be evaluated - it will be displayed as is. ::: warning Before Vitest 2.1, your `typecheck.include` overrode the `include` pattern, so your runtime tests did not actually run; they were only type-checked. Since Vitest 2.1, if your `include` and `typecheck.include` overlap, Vitest will report type tests and runtime tests as separate entries. ::: Using CLI flags, like `--allowOnly` and `-t` are also supported for type checking. ```ts import { assertType, expectTypeOf } from 'vitest' import { mount } from './mount.js' test('my types work properly', () => { expectTypeOf(mount).toBeFunction() expectTypeOf(mount).parameter(0).toMatchTypeOf<{ name: string }>() // @ts-expect-error name is a string assertType(mount({ name: 42 })) }) ``` Any type error triggered inside a test file will be treated as a test error, so you can use any type trick you want to test types of your project. You can see a list of possible matchers in [API section](/api/expect-typeof). ## Reading Errors If you are using `expectTypeOf` API, refer to the [expect-type documentation on its error messages](https://github.com/mmkal/expect-type#error-messages). When types don't match, `.toEqualTypeOf` and `.toMatchTypeOf` use a special helper type to produce error messages that are as actionable as possible. But there's a bit of an nuance to understanding them. Since the assertions are written "fluently", the failure should be on the "expected" type, not the "actual" type (`expect().toEqualTypeOf()`). This means that type errors can be a little confusing - so this library produces a `MismatchInfo` type to try to make explicit what the expectation is. For example: ```ts expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>() ``` Is an assertion that will fail, since `{a: 1}` has type `{a: number}` and not `{a: string}`. The error message in this case will read something like this: ``` test/test.ts:999:999 - error TS2344: Type '{ a: string; }' does not satisfy the constraint '{ a: \\"Expected: string, Actual: number\\"; }'. Types of property 'a' are incompatible. Type 'string' is not assignable to type '\\"Expected: string, Actual: number\\"'. 999 expectTypeOf({a: 1}).toEqualTypeOf<{a: string}>() ``` Note that the type constraint reported is a human-readable messaging specifying both the "expected" and "actual" types. Rather than taking the sentence `Types of property 'a' are incompatible // Type 'string' is not assignable to type "Expected: string, Actual: number"` literally - just look at the property name (`'a'`) and the message: `Expected: string, Actual: number`. This will tell you what's wrong, in most cases. Extremely complex types will of course be more effort to debug, and may require some experimentation. Please [raise an issue](https://github.com/mmkal/expect-type) if the error messages are actually misleading. The `toBe...` methods (like `toBeString`, `toBeNumber`, `toBeVoid` etc.) fail by resolving to a non-callable type when the `Actual` type under test doesn't match up. For example, the failure for an assertion like `expectTypeOf(1).toBeString()` will look something like this: ``` test/test.ts:999:999 - error TS2349: This expression is not callable. Type 'ExpectString' has no call signatures. 999 expectTypeOf(1).toBeString() ~~~~~~~~~~ ``` The `This expression is not callable` part isn't all that helpful - the meaningful error is the next line, `Type 'ExpectString has no call signatures`. This essentially means you passed a number but asserted it should be a string. If TypeScript added support for ["throw" types](https://github.com/microsoft/TypeScript/pull/40468) these error messages could be improved significantly. Until then they will take a certain amount of squinting. #### Concrete "expected" objects vs typeargs Error messages for an assertion like this: ```ts expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' }) ``` Will be less helpful than for an assertion like this: ```ts expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>() ``` This is because the TypeScript compiler needs to infer the typearg for the `.toEqualTypeOf({a: ''})` style, and this library can only mark it as a failure by comparing it against a generic `Mismatch` type. So, where possible, use a typearg rather than a concrete type for `.toEqualTypeOf` and `toMatchTypeOf`. If it's much more convenient to compare two concrete types, you can use `typeof`: ```ts const one = valueFromFunctionOne({ some: { complex: inputs } }) const two = valueFromFunctionTwo({ some: { other: inputs } }) expectTypeOf(one).toEqualTypeof() ``` If you find it hard working with `expectTypeOf` API and figuring out errors, you can always use more simple `assertType` API: ```ts const answer = 42 assertType(answer) // @ts-expect-error answer is not a string assertType(answer) ``` ::: tip When using `@ts-expect-error` syntax, you might want to make sure that you didn't make a typo. You can do that by including your type files in [`test.include`](/config/#include) config option, so Vitest will also actually *run* these tests and fail with `ReferenceError`. This will pass, because it expects an error, but the word “answer” has a typo, so it's a false positive error: ```ts // @ts-expect-error answer is not a string assertType(answr) // ``` ::: ## Run Typechecking To enable typechecking, just add [`--typecheck`](/config/#typecheck) flag to your Vitest command in `package.json`: ```json { "scripts": { "test": "vitest --typecheck" } } ``` Now you can run typecheck: ::: code-group ```bash [npm] npm run test ``` ```bash [yarn] yarn test ``` ```bash [pnpm] pnpm run test ``` ```bash [bun] bun test ``` ::: Vitest uses `tsc --noEmit` or `vue-tsc --noEmit`, depending on your configuration, so you can remove these scripts from your pipeline.