--- 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 or compile these files, they are only statically analyzed by the compiler, and because of that you cannot use any dynamic statements. Meaning, you cannot use dynamic test names, and `test.each`, `test.runIf`, `test.skipIf`, `test.concurrent` APIs. But you can use other APIs, like `test`, `describe`, `.only`, `.skip` and `.todo`. 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.