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

Feature: add a new assertion that uses assignability checking #18

Closed
DetachHead opened this issue Mar 28, 2021 · 12 comments
Closed

Feature: add a new assertion that uses assignability checking #18

DetachHead opened this issue Mar 28, 2021 · 12 comments
Labels
status: accepting prs Please, send a pull request to resolve this! 🙏 type: feature New enhancement or request 🚀

Comments

@DetachHead
Copy link

types should be compared using the compiler API or something. using a string comparison causes many problems when you aren't sure exactly how the compiler will resolve a type.

some examples:

 Expected type to be: 1|2, got: 1 | 2 
type Foo = { foo: number; bar: number }

//fails: Expected type to be: {foo: number; bar: number}, got: Foo
const foo = {} as Foo // $ExpectType {foo: number; bar: number}

since typescript is structurally typed, it doesn't make sense for it to behave that way.

@JoshuaKGoldberg JoshuaKGoldberg added status: accepting prs Please, send a pull request to resolve this! 🙏 type: bug Something isn't working :( 🐛 type: feature New enhancement or request 🚀 status: in discussion Not yet ready for implementation or a pull request and removed type: bug Something isn't working :( 🐛 status: accepting prs Please, send a pull request to resolve this! 🙏 labels Aug 21, 2021
@JoshuaKGoldberg
Copy link
Owner

Indeed, this is a tricky one. At first it does seem like a bug... but then knowing that {foo: number; bar: number} is the same as Foo almost seems like a feature request?

Let's wait to get a bit more feedback. It's not clear to me that we actually would want to disagree with the TypeScript compiler on the exact phrasing of a type by default. Maybe a separate command like $ExpectTypeStructure would be best? Not sure.

@danvk
Copy link
Collaborator

danvk commented Mar 20, 2022

Anders handled this in dtslint by supporting multiple alternatives, e.g. $ExpectType 1|2 || 2|1.

@JoshuaKGoldberg
Copy link
Owner

Coming back to this:

checked by the compiler API

There is no compiler API yet for type assignability checking ("is X assignable to Y?"). We're blocked on my favorite TypeScript issue: microsoft/TypeScript#9879

Marking this particular feature request as blocked. We can bikeshed the name, semantics, and any potential default behavior changes of the command once TypeScript provides an assignability API. If it ever does. 😢

@JoshuaKGoldberg JoshuaKGoldberg added status: blocked on external API Waiting for an external dependency... and removed status: in discussion Not yet ready for implementation or a pull request labels Mar 20, 2022
@danvk
Copy link
Collaborator

danvk commented Apr 20, 2022

As a contrary take on this, I actually like that this plugin does string comparisons. There are many ways to display the same type, and your library does have some control over which one the user sees (see this post). So if you care about how your types display, you need some way to test that. And this plugin is great for testing type display!

If you specifically want to test assignability, you have other options, e.g. something like:

function expectType<T>(x: T) {}

const four = 4;
expectType<number>(four);

@DetachHead
Copy link
Author

the problem with a solution like that is that it doesn't check for an exact match, but rather any subtype:

const four: 4 = 4
expectType<number>(four) //no error

you can try to make one that checks for an exact match using two generics, but that's quite the rabbit hole

i do agree though that there are definitely use cases for testing the way a type is displayed, so i guess the ideal solution is to have both options

@JoshuaKGoldberg
Copy link
Owner

JoshuaKGoldberg commented Dec 19, 2023

As of microsoft/TypeScript#56448, we can consider this feature unblocked! (also, typescript-eslint/typescript-eslint#7936, heh)

This shouldn't be the default behavior for the plugin. It should be a separate type of assertion. Let's say $ExpectTypeAssignableTo?

If someone is attempting to author a PR for this and TypeScript types don't yet include isTypeAssignableTo, feel free to say (checker as any).isTypeAssignableTo in the interim.

cc @danvk

@JoshuaKGoldberg JoshuaKGoldberg added status: accepting prs Please, send a pull request to resolve this! 🙏 and removed status: blocked on external API Waiting for an external dependency... labels Dec 19, 2023
@JoshuaKGoldberg JoshuaKGoldberg changed the title types are checked by a simple string comparison Feature: add a new assertion that uses assignability checking Dec 19, 2023
@jakebailey
Copy link

How are you planning on building up the type from just the string? AFAIK there is no way to ask the checker for any type that isn't derived from what was loaded in the program.

(The original issue is one that would be fixed by adopting the union normalization I wrote and is now filed as #108.)

@JoshuaKGoldberg
Copy link
Owner

Hmm that's a good point. Maybe: creating a new source file with almost the same name (or updating the existing one, depending on the API(s)?), setting its text to be similar, and grabbing that type?

@jakebailey
Copy link

That sounds like a bad time compared to just using an expectType function that allows you to write the code in-place like the example above or the libraries linked in the README.

(I would honestly prefer people tend toward writing those and getting feedback directly from tsc rather than relying on ExpectType comments and was relieved when we ditched ExpectError in favor of // @ts-expect-error on DT.)

@JoshuaKGoldberg
Copy link
Owner

Makes sense, thanks! I'll close this for now. If anybody has strong opinions they can always post back or file a new issue.

@JoshuaKGoldberg JoshuaKGoldberg closed this as not planned Won't fix, can't repro, duplicate, stale Dec 19, 2023
@JoshuaKGoldberg
Copy link
Owner

@all-contributors please add @DetachHead for ideas.

🤖 Beep boop! This comment was added automatically by all-contributors-auto-action.
Not all contributions can be detected from Git & GitHub alone. Please comment any missing contribution types this bot missed.
...and of course, thank you for contributing! 💙

Copy link
Contributor

@JoshuaKGoldberg

I've put up a pull request to add @DetachHead! 🎉

I couldn't determine any contributions to add, did you specify any contributions?
Please make sure to use valid contribution names.

JoshuaKGoldberg pushed a commit that referenced this issue Jan 17, 2024
Adds @DetachHead as a contributor for ideas.

This was requested by JoshuaKGoldberg [in this
comment](#18 (comment))

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: accepting prs Please, send a pull request to resolve this! 🙏 type: feature New enhancement or request 🚀
Projects
None yet
Development

No branches or pull requests

4 participants