Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Testing types with expectTypeOf and assertType #1954

Open
sheremet-va opened this issue Sep 2, 2022 · 11 comments · Fixed by #2107
Open

[RFC] Testing types with expectTypeOf and assertType #1954

sheremet-va opened this issue Sep 2, 2022 · 11 comments · Fixed by #2107
Labels
enhancement New feature or request rfc

Comments

@sheremet-va
Copy link
Member

sheremet-va commented Sep 2, 2022

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

@sheremet-va sheremet-va added the enhancement New feature or request label Sep 2, 2022
@sheremet-va sheremet-va pinned this issue Sep 2, 2022
@antfu antfu added the rfc label Sep 7, 2022
@crutchcorn
Copy link

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.

@orta
Copy link

orta commented Sep 7, 2022

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.

@MaloLebrin
Copy link

MaloLebrin commented Sep 7, 2022

Awesome idea (expect-types looks cool as suggested by @orta)

Can we test generics types ? for exemple

expect-types(object).toBeTypeOf(UserInterface)

@HiDeoo
Copy link

HiDeoo commented Sep 7, 2022

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.

@skarab42
Copy link
Contributor

skarab42 commented Sep 7, 2022

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

@Sepush
Copy link

Sepush commented Sep 7, 2022

I want this for days, looks great!

@sheremet-va
Copy link
Member Author

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.

@skarab42
Copy link
Contributor

skarab42 commented Sep 7, 2022

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.

@xiaoxiangmoe
Copy link

Why not just use tsc or vue-tsc with @ts-expect-error to type check

@sheremet-va
Copy link
Member Author

The first iteration is released in Vitest 0.25.0. Feel free to make suggestions on improving its support.

@sheremet-va sheremet-va reopened this Nov 7, 2022
@markwhitfeld
Copy link

markwhitfeld commented Nov 10, 2022

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request rfc
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants