Skip to content

fix(recommended): stop no-unused-vars reporting using declarations - #199

Merged
saberzero1 merged 2 commits into
obsidianmd:masterfrom
mnaoumov:fix-using
Oct 7, 2026
Merged

saberzero1 merged 2 commits into
obsidianmd:masterfrom
mnaoumov:fix-using

Conversation

@mnaoumov

@mnaoumov mnaoumov commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

A using / await using binding is consumed through Symbol.dispose at block exit, but the syntax still requires a name. The recommended @typescript-eslint/no-unused-vars entry therefore reported every one of them as assigned but never used. This PR enables ignoreUsingDeclarations.

The option first shipped in typescript-eslint 8.46.0, and the rule's schema rejects unknown keys. The plugin keeps its typescript-eslint floor at ^8.35.1 and sets the option only when the installed rule's schema declares it. On older versions, using declarations are still reported, as before.

The options now live in ruleOptions.ts, so the test exercises exactly what the recommended config ships. varsIgnorePattern is deliberately not added, so an underscore-prefixed dead binding is still reported.

The @typescript-eslint/* dependencies and dev dependencies move to ^8.46.0, since the tests pass the option directly. All of them are locked at 8.58.2, the version typescript-eslint already resolved to.

@mnaoumov
mnaoumov requested a review from saberzero1 September 25, 2026 06:33
Comment thread package.json Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should these two be bumped as well so they stay in sync?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes. @typescript-eslint/types and @typescript-eslint/utils now move to ^8.46.0 along with the three dev copies.

Leaving them behind was what split the tree. types and utils were locked at 8.33.1 and hoisted, and every newer @typescript-eslint/* package pins its siblings to its own exact version, so npm nested a second full set under each one. All five are now locked at 8.58.2, the same version typescript-eslint itself already resolves to, so the tree holds one copy of each. These are regular dependencies, not peers, so raising them does not constrain consumers.

Comment thread package.json Outdated
"eslint": ">=9.19.0",
"obsidian": "1.8.7",
"typescript-eslint": "^8.35.1"
"typescript-eslint": "^8.46.0"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Are there special considerations for upgrading peerDependencies? I think consumers that have typescript-eslint pinned to a version below this will get an error with this change.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch. It was a real problem, just not the one I expected, so I've reverted the peer bump.

ignoreUsingDeclarations first shipped in typescript-eslint 8.46.0. The rule's option schema has additionalProperties: false, so an older version rejects the whole config instead of ignoring the unknown key. That's why I raised the floor.

I checked what a consumer on 8.45.0 actually gets. npm does not refuse the install. typescript-eslint is both a dependency and a peer of this plugin, so npm quietly nests its own newer copy under the plugin. The recommended config alone then lints fine. But a consumer who layers their own typescript-eslint configs on top, as docs/configuration.md shows, fails with:

ConfigError: Config "typescript-eslint/base": Key "plugins": Cannot redefine plugin "@typescript-eslint".

So I dropped the floor bump. The dependency and the peer are back at ^8.35.1. The option is now set only when the installed rule's schema declares it (lib/ruleOptions.ts). On 8.35 to 8.45, using declarations are still reported, exactly as before this PR. From 8.46.0 on, they're ignored. Here is the packed tarball checked against a consumer on each version, using the layered config from the docs:

  • 8.45.0: typescript-eslint dedupes to the consumer's copy and the config loads. Unused using bindings are still reported.
  • 8.46.0: the same config loads, and only the genuinely dead const _dead = 1 is reported.

The dev copies stay at ^8.46.0, because the tests pass the option to the rule directly.

Comment thread package-lock.json Outdated
"version": "8.33.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz",
"integrity": "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==",
"version": "8.70.1",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Where is 8.70.1 coming from? This is different than the version specified in the package.json.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It was whatever ^8.46.0 resolved to on the day I reinstalled. 8.70.1 was the latest 8.x at the time. The lockfile records the resolved version, not the range. It still wasn't right, though. typescript-eslint itself stayed locked at 8.58.2 and carried its own nested 8.58.2 set, so the tree held two versions of every @typescript-eslint/* package.

I've re-locked them. Every @typescript-eslint/* entry is now 8.58.2, the version typescript-eslint was already locked at, so the lockfile diff only removes the old 8.33.1 set and the nested duplicates. That also brought back master's expected output for the await-thenable suggestion test. The earlier change there was only a whitespace difference in 8.70.1.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The configuration, dependency requirements, and regression coverage are consistent with the intended behavior.

Review effort: Balanced
Findings: None

What changed in this PR

Updates the recommended TypeScript ESLint configuration to allow unused using declarations.

Changes:

  • Enables ignoreUsingDeclarations.
  • Adds using and await using coverage.
  • Raises TypeScript ESLint dependency floors and updates test output.
File Description
lib/​index.ts Applies shared unused-variable options.
lib/​ruleOptions.ts Defines the new rule options.
tests/​typescriptEslintRules.test.ts Tests declaration handling.
tests/​typescriptEslintTypeCheckedRules.test.ts Updates suggestion output.
package.json Raises dependency floors.
package-lock.json Updates resolved dependencies.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The umbrella dependency still permits unsupported versions, and an upgraded-rule test expectation remains stale.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)

Comment thread lib/ruleOptions.ts
export const noUnusedVarsOptions = [{
args: "none",
ignoreRestSiblings: true,
...(supportsIgnoreUsingDeclarations ? { ignoreUsingDeclarations: true } : {}),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is on purpose. Raising the floor to 8.46.0 is the change I reverted after the peer question above. With typescript-eslint both a dependency and a peer, a consumer pinned below 8.46.0 gets a second nested copy, and the layered config from docs/configuration.md then fails with Cannot redefine plugin "@typescript-eslint".

So a consumer on 8.35 to 8.45 keeps exactly the behaviour they have today, and anyone on 8.46.0 or later, which is what a fresh install resolves to, gets the fix. Upgrading typescript-eslint is enough to pick it up.

A `using` / `await using` binding is consumed through `Symbol.dispose`
at block exit, yet the syntax still requires a name, so the recommended
`@typescript-eslint/no-unused-vars` entry reported every one of them as
assigned but never used. Enable `ignoreUsingDeclarations`.

The option first shipped in typescript-eslint 8.46.0, and the rule's
schema rejects unknown keys, so an older copy would fail the whole config
as invalid. The dependency and peer floors of `typescript-eslint` move to
^8.46.0, and the dev copies used by the rule tests move with them.

The options now live in `ruleOptions.ts` so the test exercises exactly
what the recommended config ships. `varsIgnorePattern` is deliberately
not added: an underscore-prefixed dead binding is still reported.

The newer typescript-eslint trims the whitespace left behind by the
await-thenable `removeAwait` suggestion, so that pinned output is updated.
Raising the typescript-eslint floor to 8.46.0 did not make npm refuse an
older copy. Because the package is also a regular dependency, npm quietly
nested a second copy under the plugin. A consumer who layers their own
tseslint configs, as docs/configuration.md shows, then got "Cannot
redefine plugin @typescript-eslint".

Keep the floor where it was. Set ignoreUsingDeclarations only when the
installed no-unused-vars schema declares it. On 8.35-8.45 a using
declaration is still reported, as before this change.

Lock every @typescript-eslint package at 8.58.2, the version
typescript-eslint was already locked at, so the tree holds one copy.
Move the types and utils dependencies to ^8.46.0 alongside the dev
copies. At 8.58.2 the await-thenable suggestion still leaves the double
space, so that test output goes back to master's.
@tgrosinger

Copy link
Copy Markdown
Collaborator

@saberzero1 what do you think of this PR? I'd like to merge this once you approve instead of https://github.com/obsidianmd/community-workers/pull/52

@saberzero1 saberzero1 self-assigned this Oct 7, 2026
@saberzero1
saberzero1 merged commit 837b01d into obsidianmd:master Oct 7, 2026
4 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants