vitest
vitest copied to clipboard
[RFC] Testing types with expectTypeOf and assertType
Clear and concise description of the problem
Currently users have to come up with their own solutions to test types. Fo example, Vue defines a set of small utils:
export function expectType<T>(value: T): void
export function expectError<T>(value: T): void
export function expectAssignable<T, T2 extends T = T>(value: T2): void
This is not helpful for people who are coming into the world of types and testing their types. We want to provide a better developer experience.
Suggested solution
Vitest could provide an API for testing TypeScript types, since Vitest can already run typescript files.
Vitest can provide API, similar to expect
, inspired by expect-type
package:
expectTypeOf({a: 1}).toEqual<{a: number}>()
expectTypeOf({a: 1}).not.toMatch({b: 1})
Vitest can also provide API, similar to what Vue is using:
assertType<Type>(obj)
// @ts-expect-error
assertType<Type>(obj)
That way Vitest can provide similar set of tools that it already provides for runtime tests (expect
and assert
APIs).
Vitest will not fail, if tests are running with vitest
and there is a type error, because there is no type checking involved, when running regular tests.
Vitest will fail, if tests are running with vitest type
and there is a type error. When running type
command, Vitest will run tsc
under the hood. There will be an option in config to change command:
{
test: {
type: {
command?: string // tsc --noEmit by default
// potentially other options?
}
}
}
It will be recommended to have two pipelines for testing your application (currently this practice already exists, but tests are running with tsc
or similar tool directly).
I love this API. I've often felt (and have seen similar sentiment) that writing TypeScript for libraries is an over-exhaustive onus on library maintainers, primarily due to the lack of polished tooling surrounding the verification of types.
This would be a massive reason to migrate to Vitest for those of us that are looking for an all-in-one API.
This is a pretty solid idea (expect-types looks cool)
I wonder if you're going to consider a command like vitest type
then it could be worth exploring the TS LSP API on the test files to do things like snapshots for the types?
import thing from "thingy"
expect(thing).toHaveHoverInfoSnapshot(`const thing: Thing`)
( Effectively replicating the twoslash hovers in a test as an example )
It will take as much time as a tsc run (which it sounds like you may be doing anyway) and then the particular LSP calls you need to use which should be fast.
Awesome idea (expect-types looks cool as suggested by @orta)
Can we test generics types ? for exemple
expect-types(object).toBeTypeOf(UserInterface)
Love the idea and having a built-in snapshot support (like the example from @orta) would indeed be amazing.
tsd also provides a printType()
helper which can be handy.
Very cool, I like it a lot. By the way, I made a plugin recently that implements both APIs in Vitest. https://github.com/skarab42/vite-plugin-vitest-typescript-assert
I want this for days, looks great!
Very cool, I like it a lot. By the way, I made a plugin recently that implements both APIs in Vitest. skarab42/vite-plugin-vitest-typescript-assert
I see that your plugin and tsd are using patched version of typescript. I wonder if it's possible to avoid that? My concern is that it wouldn't be possible to run types with Volar, for example. First version of this proposal expected developers to use types.command
option, so users can replace tsc
with vue-tsc
, for example.
But of course, we can provide some kind of Provider
interface to extend for custom use in the future.
I wonder if it's possible to avoid that?
Unfortunately as long as the TS team doesn't make some functions in the TypeChecker
publicly available, we won't be able to do anything more than what tsc --noEmit
already does (which might be enough for many users), e.g. strict equality comparison.
Why not just use tsc or vue-tsc with @ts-expect-error
to type check
The first iteration is released in Vitest 0.25.0. Feel free to make suggestions on improving its support.
This is definitely my favourite way to test types: https://github.com/microsoft/DefinitelyTyped-tools/blob/master/packages/dtslint/README.md#write-tests As far as I know, it is the only way to test the inferred type of a function parameter. All the other techniques can only test return types (as far as I can see, but I have never delved too deep due to this limitation).
I use this extensively in my library tests:
You can see here that I am testing the type inferred for the function parameters from the function's contextual type inferrence. I don't know of any other library that can do this. Here, I am essentially testing the IntelliSense (and therefore the developer experience). The syntax uses comments to identify nodes of the typescript AST that need to have their type confirmed. I just wish that they also supported an inline comment syntax too.