JoshuaKGoldberg / eslint-plugin-expect-type

ESLint plugin with ^? Twoslash, $ExpectError, and $ExpectType type assertions. 🧩
Apache License 2.0
109 stars 5 forks source link

Checking errors via `@ts-expect-error`? #65

Open rauschma opened 1 year ago

rauschma commented 1 year ago

In my TypeScript book, I’m using @ts-expect-error with error messages to point out if there are errors – e.g.:

function func(value: unknown) {
  // @ts-expect-error: Object is of type 'unknown'.
  value.toFixed(2);

  // Type assertion:
  (value as number).toFixed(2); // OK
}

Benefit: Very similar to assert.throws() in that type checking doesn’t fail if everything is as expected.

All examples from my book: https://gist.github.com/rauschma/4d1ee06e47e03545d4c4b31b59700786

JoshuaKGoldberg commented 1 year ago

Sorry for the delay - I like the idea! For visibility, https://github.com/microsoft/TypeScript/issues/19139 is a long-standing feature request on the TypeScript side to add this kind of check natively. It's blocked because TypeScript's error codes and diagnostic message texts are not stable. Having a userland tool such as eslint-plugin-expect-type implement this functionality would be good.

A few things we should figure out...

My instinct is to make the rule strict by default so we don't have a plethora of odd user forms. Perhaps only the three following formats:

...where if message starts with /, it's treated as a regular expression.

What do you think @rauschma?

Another side note: https://github.com/microsoft/TypeScript/issues/38370 tracks quirks in the TypeScript side around parsing lines. Beware to any implementer of this issue that it's easy to get the edge cases wrong. (trust me, I know! 😄)

Edit 12/4: Oh, and...

rauschma commented 1 year ago

For reference, this is what an error message looks like in the TS Playground:

Property 'hello' does not exist on type '"abc"'.(2339)

This is what it looks like at the command line (tsc):

main.ts:1:7 - error TS2339: Property 'hello' does not exist on type '"abc"'.

Thoughts:

Examples (suffixed error numbers):

// @ts-expect-error: Property 'hello' does not exist on type '"abc"'. (TS2339)
// @ts-expect-error: (TS2339)
// @ts-expect-error: Property 'hello' does not exist [...] (TS2339)
// @ts-expect-error: Property 'hello' does not exist [...]

Examples (prefixed error numbers):

// @ts-expect-error TS2339: Property 'hello' does not exist on type '"abc"'.
// @ts-expect-error TS2339
// @ts-expect-error TS2339: Property 'hello' does not exist [...]
// @ts-expect-error: Property 'hello' does not exist [...]

What are your thoughts?

bradzacher commented 1 year ago

Note that there's no api in TS to speculatively ask questions. This is important because it means that the diagnostics and types you get are what you get.

Put another way - if TS suppresses an error - it's gone.

You would need to manually re-check the code without the suppression in order to get the error. Which would make this a lot harder (and slower) to do than with a custom comment.

I'd assume this is why they used custom comments in the dtslint project.

rauschma commented 1 year ago

@bradzacher Right! That reminds me of the workaround that I used when I implemented similar functionality via the tsc API: I replaced each @ts-expect-error in the code with %ts-expect-error and then collected errors.

danvk commented 1 year ago

Here's the code in literate-ts that I used to match errors in Effective TypeScript. The sequence was:

IIRC, this never worked perfectly, but worked well enough to be useful in final editing.

https://github.com/danvk/literate-ts/blob/50393398f12252e3985b37d9e4b007a7a626ea4b/src/ts-checker.ts#L72-L138

JoshuaKGoldberg commented 1 year ago

This limitation is a little irksome. Filed https://github.com/microsoft/TypeScript/issues/51749.