Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(eslint-plugin): [no-unused-var] handle implicit exports in declaration files#10714

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

Conversation

ronami
Copy link
Member

@ronamironami commentedJan 26, 2025
edited
Loading

PR Checklist

Overview

This PR continues#8611 and attempts to tackle#2867.

Note that I'm far from having a thorough understanding of how TypeScript handles exported values/types from a.d.ts file, and this seems to have a lot of undescribed edge cases, so I'm mainly basing this off on trying out edge cases and reverse engineering this locally.

Some notes/thoughts:

@typescript-eslint
Copy link
Contributor

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.

@netlifyNetlify
Copy link

netlifybot commentedJan 26, 2025
edited
Loading

Deploy Preview fortypescript-eslint ready!

NameLink
🔨 Latest commitf84ded5
🔍 Latest deploy loghttps://app.netlify.com/sites/typescript-eslint/deploys/67c547440a76ca000827e4b7
😎 Deploy Previewhttps://deploy-preview-10714--typescript-eslint.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 99 (🟢 up 1 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (🟢 up 8 from production)
SEO: 98 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to yourNetlify site configuration.

@nx-cloudNx Cloud
Copy link

nx-cloudbot commentedJan 26, 2025
edited
Loading

View yourCI Pipeline Execution ↗ for commitf84ded5.

CommandStatusDurationResult
nx run-many --target=build --exclude website --...✅ Succeeded4sView ↗
nx run-many --target=clean✅ Succeeded10sView ↗

☁️Nx Cloud last updated this comment at2025-03-03 06:23:15 UTC

@codecovCodecov
Copy link

codecovbot commentedJan 26, 2025
edited
Loading

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 87.46%. Comparing base(9e8828b) to head(f84ded5).
Report is 102 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@##             main   #10714      +/-   ##==========================================+ Coverage   87.19%   87.46%   +0.27%==========================================  Files         450      469      +19       Lines       15632    16073     +441       Branches     4570     4656      +86     ==========================================+ Hits        13630    14058     +428- Misses       1645     1658      +13  Partials      357      357
FlagCoverage Δ
unittest87.46% <100.00%> (+0.27%)⬆️

Flags with carried forward coverage won't be shown.Click here to find out more.

Files with missing linesCoverage Δ
packages/eslint-plugin/src/rules/no-unused-vars.ts99.09% <100.00%> (+0.09%)⬆️

... and65 files with indirect coverage changes

// declaration file handling
[ambientDeclarationSelector(AST_NODE_TYPES.Program, true)](
//top-leveldeclaration file handling
[ambientDeclarationSelector(AST_NODE_TYPES.Program)](
Copy link
MemberAuthor

@ronamironamiJan 26, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Testing various edge cases, I think that only checking `declare'd module-level values creates some incorrect reports (playground link).

Removing this didn't cause any tests to fail, though I could be missing an edge case.

JoshuaKGoldberg reacted with thumbs up emoji
Comment on lines +571 to +578
const moduleDecl = nullThrows(
node.parent,
NullThrowsReasons.MissingParent,
) as TSESTree.Program;

if (checkForOverridingExportStatements(moduleDecl)) {
return;
}
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This addition is so the rule would report the following (playground link):

// should be reported but doesn'tdeclareclassFoo{}export{}

Along with not reporting on the following (playground link):

// reported but shouldn'tclassFoo{}// even though this shows up as a compiler error, this isn't marked as used// uncomment the code below and TypeScript would mark this as unused:// export {};

JoshuaKGoldberg reacted with thumbs up emoji
Comment on lines 616 to 629
[ambientDeclarationSelector('TSModuleDeclaration > TSModuleBlock')](
node: DeclarationSelectorNode,
): void {
if (!isDefinitionFile(context.filename)) {
return;
}
const moduleDecl = nullThrows(
node.parent.parent,
NullThrowsReasons.MissingParent,
) as TSESTree.TSModuleDeclaration;

if (checkForOverridingExportStatements(moduleDecl)) {
return;
}
Copy link
MemberAuthor

@ronamironamiFeb 2, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This addition is for not reporting the following (playground link):

exportnamespaceFoo{// reported but shouldn'tconstfoo:1234;}

Comment on lines 587 to 594
const moduleDecl = nullThrows(
node.parent.parent,
NullThrowsReasons.MissingParent,
) as TSESTree.TSModuleDeclaration;

if (checkForOverridingExportStatements(moduleDecl)) {
return;
}
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is necessary so the following is reported (playground link):

exportdeclarenamespaceFoo{namespaceBar{namespaceBaz{// should be reported but isn'tnamespaceBam{constx=1;}export{};}}}

JoshuaKGoldberg reacted with thumbs up emoji
JoshuaKGoldberg
JoshuaKGoldberg previously approved these changesFeb 17, 2025
Copy link
Member

@JoshuaKGoldbergJoshuaKGoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Whew! What a PR. This is a tricky rule. I had to go in and out of the old & new code a few times to get a feel for it.

I think everything you're saying makes sense. As I understand it, the main changes around the newhasOverridingExportStatement & the removal of the no-longer-necessary child selectors seem correct. Anything that reducesambientDeclarationSelector's complexity is off to a good start. 😄

👍 from me on all the edge cases as described. I think we should get another review from @typescript-eslint/triage-team just to be thorough.

Darth Vader saying 'MOST IMPRESSIVE'

ronami reacted with thumbs up emojironami reacted with heart emoji
@@ -144,7 +144,10 @@ export default createRule<Options, MessageIds>({
},
defaultOptions: [{}],
create(context, [firstOption]) {
const MODULE_DECL_CACHE = new Map<TSESTree.TSModuleDeclaration, boolean>();
const MODULE_DECL_CACHE = new Map<
TSESTree.Program | TSESTree.TSModuleDeclaration,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

[Refactor] The.body seems to be assumed to always exist in code. So I think anywhere that refers to theTSModuleDeclaration type can assume this:

typeModuleDeclarationWithBody=MakeRequired<TSESTree.TSModuleDeclaration,'body'>;
Suggested change
TSESTree.Program|TSESTree.TSModuleDeclaration,
TSESTree.Program|ModuleDeclarationWithBody,

...which means the'Module declarations with no body are filtered out by the rule'nullThrows can be removed.

(unless, did I misinterpret?)

ronami reacted with eyes emoji
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Nice! I've updated the PR with your suggestion, thanks 👍

@JoshuaKGoldbergJoshuaKGoldberg added the 1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we merge labelFeb 17, 2025
@JoshuaKGoldbergJoshuaKGoldberg requested a review froma teamFebruary 17, 2025 13:11
@github-actionsgithub-actionsbot removed the 1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we merge labelFeb 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

[Praise] Really thorough investigation and tests. Nicely done! 👏

ronami reacted with heart emoji
@JoshuaKGoldbergJoshuaKGoldberg added the 1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we merge labelFeb 17, 2025
@jakebailey
Copy link
Collaborator

This would probably be a lot of work (so I can attempt to do it when I have a chance), but the thing I want to test most is to enable this rule on DT and then verify that what it says makes sense; declaration files have so many edge cases...

ronami reacted with thumbs up emoji

messageId: 'unusedVar',
},
],
filename: 'foo.d.ts',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

One thing I would do here as well is to ensure there's testing for.d.cts and.d.mts files (and their associated syntaxes).

ronami reacted with thumbs up emoji
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

constDEFINITION_EXTENSIONS=[
ts.Extension.Dts,
ts.Extension.Dcts,
ts.Extension.Dmts,
]asconst;
/**
* Check if the context file name is *.d.ts or *.d.tsx
*/
exportfunctionisDefinitionFile(fileName:string):boolean{
constlowerFileName=fileName.toLowerCase();
for(constdefinitionExtofDEFINITION_EXTENSIONS){
if(lowerFileName.endsWith(definitionExt)){
returntrue;
}
}
returnfalse;
}

It's covered by this utility so it'll work as expected so long as this utility is right!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Ah, unfortunately that function is incomplete because it doesn't handle filenames like.d.css.ts☹️

(dt-tools uses a globhttps://github.com/microsoft/DefinitelyTyped-tools/blob/1f6e243b03e6d557bf43e6312b0b8f2d47819e52/packages/utils/src/miscellany.ts#L97)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Are those other file names officially supported by TS...?
We don't really want to be in the business of guessing if a file might be a decl file.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Yes, since TS 5.0; the feature is used to provide declarations to files with non-TS extensions, e.g. a.d.css.ts file can provide types for importing a.css file.

https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#allowarbitraryextensions

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I've opened#10911 to discuss this 👍

bradzacher
bradzacher previously approved these changesFeb 17, 2025
Copy link
Member

@bradzacherbradzacher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Great work!
If you can I'd suggest trying the rule over the DefinitelyTyped repo to look for false positives. There'll be a lot of noise so worth time-boxing it -- but would be a good final validation that you haven't missed anything.

ronami reacted with thumbs up emoji
@ronami
Copy link
MemberAuthor

ronami commentedMar 2, 2025
edited
Loading

Great work! If you can I'd suggest trying the rule over the DefinitelyTyped repo to look for false positives. There'll be a lot of noise so worth time-boxing it -- but would be a good final validation that you haven't missed anything.

Thanks!

I've checked quite a bit of declaration files from definitelytyped, here are some of the types that this PR affects:

I checked only a small subset of definitelytyped's types, but I didn't find any incorrect or missing reports (I've relied on TypeScript'sxxx is declared but its value is never read. warnings).

@jakebailey
Copy link
Collaborator

On that first one, I'm actually surprised we are flaggingstateFromHTML andstateToHTML as unused; I had thought that withoutexport {} that everything was implicitly exported in a declaration file, but maybe there's nuance there? The playground links are setting the extension.d.ts so it's not that or anything.

ronami reacted with eyes emoji

@ronami
Copy link
MemberAuthor

ronami commentedMar 2, 2025
edited
Loading

On that first one, I'm actually surprised we are flaggingstateFromHTML andstateToHTML as unused; I had thought that withoutexport {} that everything was implicitly exported in a declaration file, but maybe there's nuance there? The playground links are setting the extension.d.ts so it's not that or anything.

To my understanding, in addition toexport {}, the following also prevent a declaration file from implicitly exporting everything:export { ... },export default ...,export * from '...', andexport = ....

Removing theexport default ... at the bottom removes TypeScript's (and ts-eslint's) unused reports (playground link).

@jakebailey
Copy link
Collaborator

jakebailey commentedMar 2, 2025
edited
Loading

That'd make some sense, yeah.

(Well, not thatd.ts export rules make any sense at all.)

ronami reacted with thumbs up emoji

bradzacher
bradzacher previously approved these changesMar 3, 2025
Copy link
Member

@bradzacherbradzacher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

sobeautiful

LGTM -- with the DefinitelyTyped testing I think we're good to go here.

ronami reacted with heart emoji
@bradzacher
Copy link
Member

We have some lint errors -- pls fix and we can merge!

ronami reacted with thumbs up emoji

@bradzacherbradzacher merged commitd8d4b3c intotypescript-eslint:mainMar 3, 2025
90 of 91 checks passed
renovatebot added a commit to andrei-picus-tink/auto-renovate that referenced this pull requestMar 5, 2025
| datasource | package                          | from   | to     || ---------- | -------------------------------- | ------ | ------ || npm        | @typescript-eslint/eslint-plugin | 8.24.0 | 8.26.0 || npm        | @typescript-eslint/parser        | 8.24.0 | 8.26.0 |## [v8.26.0](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/CHANGELOG.md#8260-2025-03-03)##### 🚀 Features-   **eslint-plugin:** \[unified-signatures] support ignoring overload signatures with different JSDoc comments ([#10781](typescript-eslint/typescript-eslint#10781))-   **eslint-plugin:** \[explicit-module-boundary-types] add an option to ignore overload implementations ([#10889](typescript-eslint/typescript-eslint#10889))-   **eslint-plugin:** \[no-unused-var] handle implicit exports in declaration files ([#10714](typescript-eslint/typescript-eslint#10714))-   support TypeScript 5.8 ([#10903](typescript-eslint/typescript-eslint#10903))-   **eslint-plugin:** \[no-unnecessary-type-parameters] special case tuples and parameter location arrays as single-use ([#9536](typescript-eslint/typescript-eslint#9536))##### 🩹 Fixes-   **eslint-plugin:** \[no-unnecessary-type-assertion] handle unknown ([#10875](typescript-eslint/typescript-eslint#10875))-   **eslint-plugin:** \[no-invalid-void-type] report `accessor` properties with an invalid `void` type ([#10864](typescript-eslint/typescript-eslint#10864))-   **eslint-plugin:** \[unified-signatures] does not differentiate truly private methods ([#10806](typescript-eslint/typescript-eslint#10806))##### ❤️ Thank You-   Andrea Simone Costa [@jfet97](https://github.com/jfet97)-   Dirk Luijk [@dirkluijk](https://github.com/dirkluijk)-   Ronen Amiel-   YeonJuan [@yeonjuan](https://github.com/yeonjuan)-   Yukihiro Hasegawa [@y-hsgw](https://github.com/y-hsgw)You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website.## [v8.25.0](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/CHANGELOG.md#8250-2025-02-24)##### 🚀 Features-   **eslint-plugin:** \[no-misused-spread] add suggestions ([#10719](typescript-eslint/typescript-eslint#10719))##### 🩹 Fixes-   **eslint-plugin:** \[prefer-nullish-coalescing] report on chain expressions in a ternary ([#10708](typescript-eslint/typescript-eslint#10708))-   **eslint-plugin:** \[no-deprecated] report usage of deprecated private identifiers ([#10844](typescript-eslint/typescript-eslint#10844))-   **eslint-plugin:** \[unified-signatures] handle getter-setter ([#10818](typescript-eslint/typescript-eslint#10818))##### ❤️ Thank You-   Olivier Zalmanski [@OlivierZal](https://github.com/OlivierZal)-   Ronen Amiel-   YeonJuan [@yeonjuan](https://github.com/yeonjuan)You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website.## [v8.24.1](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/CHANGELOG.md#8241-2025-02-17)##### 🩹 Fixes-   **eslint-plugin:** \[class-methods-use-this] check `accessor` methods with a function initializer ([#10796](typescript-eslint/typescript-eslint#10796))-   **eslint-plugin:** \[no-misused-promises] don't report on `static` `accessor` properties ([#10814](typescript-eslint/typescript-eslint#10814))-   **eslint-plugin:** \[no-deprecated] don't report on deprecated `accessor` property declaration ([#10813](typescript-eslint/typescript-eslint#10813))-   **eslint-plugin:** \[explicit-member-accessibility] check `accessor` class properties for missing accessibility modifier ([#10805](typescript-eslint/typescript-eslint#10805))-   **eslint-plugin:** \[explicit-module-boundary-types] check `accessor` class properties with a function initializer ([#10804](typescript-eslint/typescript-eslint#10804))-   **eslint-plugin:** \[prefer-return-this-type] check `accessor` properties with a function initializer ([#10794](typescript-eslint/typescript-eslint#10794))-   **eslint-plugin:** \[consistent-generic-constructors] check `accessor` class properties ([#10789](typescript-eslint/typescript-eslint#10789))-   **eslint-plugin:** \[no-unsafe-assignment] report on an `any` value assigned as an initializer of an `accessor` property ([#10785](typescript-eslint/typescript-eslint#10785))-   **eslint-plugin:** \[no-unnecessary-template-expression] ignore enum and enum members ([#10782](typescript-eslint/typescript-eslint#10782))-   **eslint-plugin:** \[no-inferrable-types] handle accessor ([#10780](typescript-eslint/typescript-eslint#10780))##### ❤️ Thank You-   Ronen Amiel-   YeonJuanYou can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website.
@ronamironami deleted the implicit-export-namespace-dts-unused-vars branchMarch 6, 2025 10:32
@github-actionsgithub-actionsbot locked asresolvedand limited conversation to collaboratorsMar 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@JoshuaKGoldbergJoshuaKGoldbergJoshuaKGoldberg left review comments

@jakebaileyjakebaileyjakebailey left review comments

@bradzacherbradzacherbradzacher left review comments

Assignees
No one assigned
Labels
1 approval>=1 team member has approved this PR; we're now leaving it open for more reviews before we merge
Projects
None yet
Milestone
No milestone
4 participants
@ronami@jakebailey@bradzacher@JoshuaKGoldberg

[8]ページ先頭

©2009-2025 Movatter.jp