Skip to content

fix(eslint-plugin): [unified-signatures] compare type parameters by constraint instead of name - #12741

Merged
JoshuaKGoldberg merged 3 commits into
typescript-eslint:mainfrom
Arlikhozhaev:fix/unified-signatures-constraint-comparison
Aug 30, 2026
Merged

JoshuaKGoldberg merged 3 commits into
typescript-eslint:mainfrom
Arlikhozhaev:fix/unified-signatures-constraint-comparison

Conversation

@Arlikhozhaev

@Arlikhozhaev Arlikhozhaev commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

PR Checklist

Overview

unified-signatures was comparing type parameter constraints by their AST node kind instead of the actual type.

That's why <T extends A> and <T extends B> were considered equal when both A and B were type references, even though they can represent different types.

This change reuses the existing typesAreEqual helper to compare the constraints instead, and removes the now unnecessary constraintsAreEqual helper.

This PR fixes the false positive described in #12143, where overloads with different type parameter constraints could be reported as combinable.

The other case in #12143 is <T extends string> vs <R extends string>. Those two can be combined, but the rule still compares type parameter names. To fix that we can match parameters by position, and you cannot simply rename T to R in the source text, because T might be a property name ({ T: string }).
That is a separate change, so this PR only fixes the extends A vs extends B false positive.

Added tests for type reference constraints and inline union constraints. The existing tests also continue to pass.

@typescript-eslint

Copy link
Copy Markdown
Contributor

Thanks for the PR, @Arlikhozhaev!

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 on https://opencollective.com/typescript-eslint.

@netlify

netlify Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for typescript-eslint ready!

Name Link
🔨 Latest commit 8c1a91c
🔍 Latest deploy log https://app.netlify.com/projects/typescript-eslint/deploys/6a9001fb80c28500086fb9aa
😎 Deploy Preview https://deploy-preview-12741--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 (no change from production)
Accessibility: 97 (no change from production)
Best Practices: 100 (no change from production)
SEO: 90 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@nx-cloud

nx-cloud Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 8c1a91c

Command Status Duration Result
nx run-many -t lint --projects=eslint-plugin --... ✅ Succeeded 57s View ↗
nx run-many -t lint --projects=parser,type-util... ✅ Succeeded 23s View ↗
nx run-many -t lint --projects=typescript-estre... ✅ Succeeded 28s View ↗
nx run-many -t lint --projects=ast-spec,utils,s... ✅ Succeeded 32s View ↗
nx run types:build ✅ Succeeded 1s View ↗
nx run integration-tests:test ✅ Succeeded 5s View ↗
nx run-many -t typecheck:tsgo ✅ Succeeded 7s View ↗
nx run-many -t typecheck ✅ Succeeded 7s View ↗
Additional runs (16) ✅ Succeeded ... View ↗

☁️ Nx Cloud last updated this comment at 2026-08-27 09:26:57 UTC

@codecov

codecov Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.93%. Comparing base (e18fea8) to head (8c1a91c).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12741      +/-   ##
==========================================
- Coverage   94.93%   94.93%   -0.01%     
==========================================
  Files         226      226              
  Lines       11539    11538       -1     
  Branches     3839     3838       -1     
==========================================
- Hits        10955    10954       -1     
  Misses        250      250              
  Partials      334      334              
Flag Coverage Δ
unittest 94.93% <100.00%> (-0.01%) ⬇️

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

Files with missing lines Coverage Δ
...ages/eslint-plugin/src/rules/unified-signatures.ts 92.18% <100.00%> (-0.05%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@StyleShit

Copy link
Copy Markdown
Member

Hey, please read our AI Contribution Policy and ensure your PR follows it.

@StyleShit StyleShit added awaiting response Issues waiting for a reply from the OP or another party AI Slop Please read our AI contributor guidelines: https://typescript-eslint.io/contributing/ai-policy labels Aug 20, 2026
@Arlikhozhaev

Copy link
Copy Markdown
Contributor Author

I appreciate you pointing that out. I did use AI to help summarize the PR description, but I’ve rewritten it myself now. Also, I’ll keep this in mind for future PRs. Sorry about that.

I’m just getting started with open source, so I’d really appreciate any advice on how I can make sure I’m following the project’s expectations properly in future contributions.

I enjoy contributing here and would like to keep learning and improving.

@StyleShit

Copy link
Copy Markdown
Member

Could you please also explain in the description why this is a partial fix?

@Arlikhozhaev

Copy link
Copy Markdown
Contributor Author

Updated the PR description to explain why the <T> / <R> case is left out and why it requires a separate change.

@StyleShit StyleShit removed awaiting response Issues waiting for a reply from the OP or another party AI Slop Please read our AI contributor guidelines: https://typescript-eslint.io/contributing/ai-policy labels Aug 23, 2026
Comment thread packages/eslint-plugin/src/rules/unified-signatures.ts
Comment thread packages/eslint-plugin/tests/rules/unified-signatures.test.ts Outdated
@github-actions github-actions Bot added the awaiting response Issues waiting for a reply from the OP or another party label Aug 26, 2026
@StyleShit StyleShit changed the title fix(eslint-plugin): [unified-signatures] compare type parameter constraints by type, not node kind fix(eslint-plugin): [unified-signatures] compare type parameters by constraint instead of name Aug 26, 2026
@StyleShit StyleShit removed the awaiting response Issues waiting for a reply from the OP or another party label Aug 27, 2026
@github-actions github-actions Bot added the 1 approval >=1 team member has approved this PR; we're now leaving it open for more reviews before we merge label Aug 27, 2026

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice and clean, thanks!

@JoshuaKGoldberg

JoshuaKGoldberg commented Aug 30, 2026 •

Copy link
Copy Markdown
Member

The existing tests also continue to pass.

Btw @Arlikhozhaev, it's pretty clear from your PR descriptions you're using AI to write them. They're not generally bad quality (some of the info & explanations have been quite helpful, thank you!) but they're quite verbose. Please be mindful that we have to read every single thing that comes our way - your PR descriptions, the much-lower-quality slop from other folks who're using AI, etc. It's draining. We'd appreciate it if you left out things that are self-evident - even if the AIs add them. ❤️

@JoshuaKGoldberg
JoshuaKGoldberg merged commit a2fccae into typescript-eslint:main Aug 30, 2026
43 checks passed
renovate Bot added a commit to andrei-picus-tink/auto-renovate that referenced this pull request Sep 1, 2026
| datasource | package                          | from   | to     |
| ---------- | -------------------------------- | ------ | ------ |
| npm        | @typescript-eslint/eslint-plugin | 8.67.0 | 8.69.0 |
| npm        | @typescript-eslint/parser        | 8.67.0 | 8.69.0 |


## [v8.69.0](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/CHANGELOG.md#8690-2026-08-31)

##### 🚀 Features

- **eslint-plugin:** \[no-misused-promises] add flagUnions option for checkConditionals ([#12603](typescript-eslint/typescript-eslint#12603))

##### 🩹 Fixes

- **eslint-plugin:** \[no-meaningless-void-operator] report void on non-call expressions ([#12727](typescript-eslint/typescript-eslint#12727))
- **eslint-plugin:** \[unified-signatures] compare type parameters by constraint instead of name ([#12741](typescript-eslint/typescript-eslint#12741))
- **eslint-plugin:** \[no-mixed-enums] use scope analysis instead of type checking for merged namespaces ([#12731](typescript-eslint/typescript-eslint#12731))

##### ❤️ Thank You

- Abdu Alim Arlikhozhaev [@Arlikhozhaev](https://github.com/Arlikhozhaev)
- Evyatar Daud [@StyleShit](https://github.com/StyleShit)
- Josh Goldberg ✨
- wonbeanie [@wonbeanie](https://github.com/wonbeanie)

See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.69.0) for more information.

You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website.


## [v8.68.0](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/CHANGELOG.md#8680-2026-08-24)

##### 🚀 Features

- **eslint-plugin:** \[strict-void-return] add fix suggestions ([#12086](typescript-eslint/typescript-eslint#12086))

##### 🩹 Fixes

- **eslint-plugin:** \[no-empty-object-type] ignore suggestions that result in invalid interfaces and export defaults ([#12739](typescript-eslint/typescript-eslint#12739))
- **eslint-plugin:** \[no-floating-promises] setting `ignoreVoid: false` results in false negative in ArrowFunctionExpression ([#12646](typescript-eslint/typescript-eslint#12646))
- **eslint-plugin:** \[no-unnecessary-type-assertion] prevent stack overflow in recursive types ([#12711](typescript-eslint/typescript-eslint#12711))
- **eslint-plugin:** \[unified-signatures] report identical signatures ([#12678](typescript-eslint/typescript-eslint#12678))
- **eslint-plugin:** \[return-await] prevent autofix from breaking code in arrow-functions ([#12707](typescript-eslint/typescript-eslint#12707))
- **eslint-plugin:** \[unified-signatures] deduplicate types in report ([#12656](typescript-eslint/typescript-eslint#12656))

##### ❤️ Thank You

- Evyatar Daud [@StyleShit](https://github.com/StyleShit)
- Hugo [@hugop95](https://github.com/hugop95)
- Niki [@phaux](https://github.com/phaux)
- Younsang Na [@nayounsang](https://github.com/nayounsang)

See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.68.0) for more information.

You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website.
@kirkwaiblinger

Copy link
Copy Markdown
Member

Btw @Arlikhozhaev, it's pretty clear from your PR descriptions you're using AI to write them.

In addition to JoshuaKGoldberg's comments, note that the the magic issue-closing string was removed from the issue template, so this wasn't linked to #12143 correctly.

Please follow our templates and processes 🙏

@StyleShit

StyleShit commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

note that the the magic issue-closing string was removed from the issue template

I think it was intentional, as this only partially fixes it?
See the last part of the description:

The other case in #12143 is vs . Those two can be combined, but the rule still compares type parameter names. To fix that we can match parameters by position, and you cannot simply rename T to R in the source text, because T might be a property name ({ T: string }).
That is a separate change, so this PR only fixes the extends A vs extends B false positive.

@kirkwaiblinger

Copy link
Copy Markdown
Member

Ah, my bad, then 👍

graphite-app Bot pushed a commit to oxc-project/oxc that referenced this pull request Sep 23, 2026
…26956)

Port the `unified-signatures` changes from typescript-eslint/typescript-eslint#12656, typescript-eslint/typescript-eslint#12678, and typescript-eslint/typescript-eslint#12741:

- Flatten and deduplicate union members in diagnostics, preserving necessary parentheses.
- Report identical overload signatures.
- Compare type parameter constraint text so distinct constraints such as `extends A` and `extends B` are not unified.

Includes the upstream regressions and additional cases checked against ESLint 8.70.1. Parenthesized type nodes are unwrapped to match ESTree, while diagnostics retain Oxc's paired labels. The rule remains diagnostic-only.

Validation: focused rule tests, all 62 TypeScript rule tests, and linter clippy passed. `just ready` passed the workspace check but could not finish the all-features test build: the linker ran out of disk space (`errno=28`).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

Development

Successfully merging this pull request may close these issues.

Bug: [unified-signatures] when using generic constraints, the name instead of the actual constraint is judged

4 participants