-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
[utils] Use template literal types to parse esquery selectors to automatically type complex selectors #4065
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
Comments
YES. This would be such a good type system challenge 😄 This feels like something that would be broadly useful outside of typescript-eslint for writing vanilla ESLint rules in TypeScript... I don't (yet?) know how that would be doable, but something to keep in mind maybe.
Perhaps an ESLint rule that parses the type from the selector and enforces the right type on the node? |
That was what I was something I was thinking we could do as well, yeah! That we we can handle some simpler cases with template literal types and lean on probably correct explicit types enforced via a lint rule. We could also leverage codegen to generate more selector strings. Eg we could take the type defs and generate extra defs for every node like: 'VariableDeclarator[init]'?: (
node: VariableDeclarator & {
init: NonNullable<VariableDeclarator['init']>,
},
) |
I created Perhaps this could be useful for typescript-eslint! It properly infers types for all the selectors used in See tests: You can try it online if you want! I hope this will be useful for ts-eslint. Perhaps we can use this project as a reference to implement the same functionality as built-in in ts-eslint's utils.. Or maybe we can use it as is. If you want, I can file a draft pr with the So if you have any thoughts about this, please let me know! |
@auvred do we know what the typecheck perf hit is for the types? |
I removed explicit type annotations for >90% of existing selectors in the Tested with
So it adds +2s to the |
🤔 that's really not that bad overall for a marked improvement in devx. I think this is a good thing to be added as part of our standard offering! Will it break anything if we were to just introduce it as a dependency now? People's existing annotations won't break it, right? If it will break - will need to wait for a major. If not then we could just do a feature bump addition! |
cc @bmish from eslint-community/eslint-plugin-eslint-plugin#339, thinking on what a rule to ban overly complex ESQuery selectors should consider "complex". I think it'd make sense to have "whatever Aside: |
After a quick look through my changes: there is ~130 "old" selectors (just plain AST node types + AST node types with In the group of "old" selectors I only included those that use So I didn't take into account the following listeners: // ...
return {
Identifier() { doSomeStuff() },
MemberExpression: doSomeStuff
}
In most cases, no. But there are a few places that can break, I think... For example typescript-eslint/packages/eslint-plugin/src/rules/naming-convention.ts Lines 686 to 695 in f36f682
It returns object with type createRule({
create() {
return {
Identifier(node) { /* ... */ }
// ^---------^-- we need to somehow link these two and consider that `Identifier` may be any string literal or string!
}
}
}) Currently it works only if one of the listeners is a string literal. Here is TypeScript playground link with the reproduction of this issue. Any help will be appreciated 😄 The solution linked above looks very hacky, but I can't think of any other way to do this without changing the overall |
I called it that, inspired by |
Template literal types (https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html) were released in TS 4.1. since their announcement people have done all sorts of crazy and wonderful things with them - from simple cases like auto prefixing keys to ridiculous things like SQL query parsers.
We should be able to leverage them as part of our ESLint types to automatically type the
node
argument of an ESLint rule selector.We don't need to handle every crazy case (selectors can get pretty complicated!) but at least handling things like property existence checks, sibling checks, and the
:exit
special selector would be great.For reference here are the docs on, and implementation of esquery selectors
https://github.com/estools/esquery
It's worth mentioning that if we find that template literal types are too slow or complex, an alternative might be to consider using codegen to generate a number of common cases statically. But I'd love to achieve this using template literal types if possible!
The text was updated successfully, but these errors were encountered: