Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.8k
fix(eslint-plugin): [no-invalid-void-type] don't flag function overloading withvoid
in return type annotation#10422
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Thanks for the PR,@ronami! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently onhttps://opencollective.com/typescript-eslint. |
netlifybot commentedNov 29, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
✅ Deploy Preview fortypescript-eslint ready!
To edit notification comments on pull requests, go to yourNetlify site configuration. |
nx-cloudbot commentedNov 29, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
View yourCI Pipeline Execution ↗ for commit7887cc9.
☁️Nx Cloud last updated this comment at |
codecovbot commentedNov 29, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@## main #10422 +/- ##==========================================+ Coverage 87.26% 87.30% +0.03%========================================== Files 450 451 +1 Lines 15715 15750 +35 Branches 4601 4615 +14 ==========================================+ Hits 13714 13750 +36 Misses 1645 1645+ Partials 356 355 -1
Flags with carried forward coverage won't be shown.Click here to find out more.
|
/* istanbul ignore next */ | ||
return []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Is there a preferred way to tackle this? I think this is currently an unreachable line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
#10388 - either it's reachable or it's not.
If it's not actually reachable then I'd say use type assertion(s) to tell TypeScript why it's wrong.
There might be opportunities to suggest improvements to AST types too. Example: thegetMembers(node.parent.parent)
later on has the provided type asTSESTree.Node
. But maybe somewhere in there a type could be made more specific? IsTSESTree.ExportDefaultDeclaration
's.parent
always aTSESTree.BlockStatement | TSESTree.Program
, rather than the catch-allTSESTree.Node
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Interesting! I didn't consider proposing changes/improvements to the AST types. I've found#9560, and I think it would be a good option if I could be sure the changes are correct.
To my understanding, TypeScript's AST doesn't even have an actual AST node forExportDefaultDeclaration
orExportNamedDeclaration
as they're expressed asmodifiers
.
I've looked into@babel/parser
,@swc/types
, and@oxc-project/types
(also the more technical1,2), but I didn't find anything that makes me confident this is valid in every case. I did verify@typescript-eslint
itself is type-checked successfully with these assumptions.
The stricter parent types for the AST I'd like to propose:
ExportDefaultDeclaration
andExportNamedDeclaration
should have the stricterparent
type ofTSESTree.BlockStatement | TSESTree.Program | TSESTree. TSModuleBlock
(I'm not sure ifTSESTree.BlockStatement
is an option).FunctionDeclaration
should have the stricterparent
type ofTSESTree.BlockStatement | TSESTree.ExportDefaultDeclaration | TSESTree.ExportNamedDeclaration | TSESTree.Program
.TypeScript itself doesn't have a specific
parent
forFunctionDeclaration
(it falls back to the genericts.Node
), although they do have stricter parent types for some other nodes.
How did we verify the correctness of the proposals in#6225? Also, would this type of change be considered a breaking change? I noticed that#9560 was released in v8, but it wasn't marked as abreaking change.
I'm a bit hesitant to change the AST's types, as it can potentially lead to bugs, and I would love to hear opinions on this.
I updated the PR with these changes, so it's easier to discuss them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The stricter parent types for the AST I'd like to propose:
I'd say those proposals should be a separate issue. I'm generally in favor of stricter parent types in general but we should discuss.
So I think how to handle that in this PR is up to you. Maybe either:
- Link to the issue with an
as
- Draft this PR and mark it blocked till that's resolved
How did we verify the correctness of the proposals in#6225?
Other thanyarn build
andyarn typecheck
, pretty much just manual knowledge and testing.
breaking change?
I don't think improving the types of the AST to better reflect reality is breaking. In that sense it's a "feature".
Changing theruntime value would IMO be a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
That sounds good; I'm not sure why I mixed both on the same PR; thanks! 👍
I've opened#10682, drafted this PR, and marked it as blocked.
If the issue is accepted, I'll create a new PR with the stricter parent node changes and eventually re-open this PR for review with only the relevant changes.
const id = nullThrows( | ||
node.id, | ||
'This may be null if and only if the parent is an `ExportDefaultDeclaration`.', | ||
); | ||
return id.name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thiscurrently only gets called for nodes whose parents aren'tExportDefaultDeclaration
, and so this can never benull
. If this code gets refactored, it may change, and this can throw.
I can change this to a chain-expression, though this will show up as a partially covered line by codecov.
constid=nullThrows( | |
node.id, | |
'This may be null if and only if the parent is an `ExportDefaultDeclaration`.', | |
); | |
returnid.name; | |
returnnode.id?.name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Similar to the other comment, my fallback would be to use a!
with a disable comment explaining why the types are wrong. If possible, fixing up the types to be correct would be even better.
You might find the existing uses of theMakeRequired
utils type interesting. Some places in code use for node types in similar situations. E.g.no-confusing-void-expression
has handling for return statements that must have anargument
. Maybe there's a similar flow here for functions that must have anid
?
I'm not worried about refactors. Our test coverage is so high that the cost of unnecessary safety precautions in code is IMO higher than the cost of the brittleness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm confident the only possibility ofnode.id
beingnull
(forFunctionDeclaration
orTSDeclareFunction
) is in cases where the parent node is anExportDefaultDeclaration
(also according to JavaScript's spec):
typescript-eslint/packages/ast-spec/src/base/FunctionBase.ts
Lines 51 to 58 ind24a828
/** | |
* The function's name. | |
* - For an `ArrowFunctionExpression` this is always `null`. | |
* - For a `FunctionExpression` this may be `null` if the name is omitted. | |
* - For a `FunctionDeclaration` or `TSDeclareFunction` this may be `null` if | |
* and only if the parent is an `ExportDefaultDeclaration`. | |
*/ | |
id:Identifier|null; |
I think that updating the types to be stricter here would be more challenging. I've resorted to using a!
with a disable comment and explaining why this is necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
LGTM overall! Just requesting touchups around the types /istanbul ignore
s. 🚀
/* istanbul ignore next */ | ||
return []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
#10388 - either it's reachable or it's not.
If it's not actually reachable then I'd say use type assertion(s) to tell TypeScript why it's wrong.
There might be opportunities to suggest improvements to AST types too. Example: thegetMembers(node.parent.parent)
later on has the provided type asTSESTree.Node
. But maybe somewhere in there a type could be made more specific? IsTSESTree.ExportDefaultDeclaration
's.parent
always aTSESTree.BlockStatement | TSESTree.Program
, rather than the catch-allTSESTree.Node
?
const id = nullThrows( | ||
node.id, | ||
'This may be null if and only if the parent is an `ExportDefaultDeclaration`.', | ||
); | ||
return id.name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Similar to the other comment, my fallback would be to use a!
with a disable comment explaining why the types are wrong. If possible, fixing up the types to be correct would be even better.
You might find the existing uses of theMakeRequired
utils type interesting. Some places in code use for node types in similar situations. E.g.no-confusing-void-expression
has handling for return statements that must have anargument
. Maybe there's a similar flow here for functions that must have anid
?
I'm not worried about refactors. Our test coverage is so high that the cost of unnecessary safety precautions in code is IMO higher than the cost of the brittleness.
{ | ||
code: 'type invalidVoidUnion = void | Map;', | ||
errors: [ | ||
{ | ||
column: 25, | ||
line: 1, | ||
messageId: 'invalidVoidUnionConstituent', | ||
}, | ||
], | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This test is unrelated to the PR, but it adds coverage to part of the code that is currently uncovered (it seemed small enough to be part of the PR, even if it's unrelated).
Please let me know if I should revert this part.
return getStaticMemberAccessValue(node, context); | ||
} | ||
function hasOverloadMethods( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think this may be useful as a shared utility function for different rules. Re-using this function (pretty much as is) simplifies tackling#4586 (which I'll be happy to push a PR for), for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Adding that this attempts to emulatechecker.isImplementationOfOverload()
for rules which aren't type-aware.
The no-invalid-void-type issue is beingfixed:typescript-eslint/typescript-eslint#10422
JoshuaKGoldberg left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Commented inline. Exciting! 🚀
I think just#10422 (comment) is left.
Opening for re-review, please note:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yeah I think this is great as-is. The utility has no known issues as used right now so we can cross that bridge when we get to it IMO. Awesome stuff! 🙌
b688380
intotypescript-eslint:mainUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
PR Checklist
void
in return type union for overloaded function #5752Overview
This PR addresses#5752 and adjusts the rule so it doesn't report on
void
that's used as part of the return type of a function overload implementation: