Skip to content

Fixed mapped types not being considered as homomorphic with substitution constraints - #63905

Open
Mateusz Burzyński (Andarist) wants to merge 2 commits into
microsoft:mainfrom
Andarist:fix-go/homomorphic-mapped-types-substitution-constraints
Open

Fixed mapped types not being considered as homomorphic with substitution constraints#63905
Mateusz Burzyński (Andarist) wants to merge 2 commits into
microsoft:mainfrom
Andarist:fix-go/homomorphic-mapped-types-substitution-constraints

Conversation

@Andarist

@Andarist Mateusz Burzyński (Andarist) commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

ports microsoft/typescript-go#4596
fixes #63132

What

This PR fixes the issue where conditionals like this keyof T extends X ? Truthy : Falsy would make { [K in keyof T: T[K] } not being recognized as homomorphic within the Truthy branch of the conditional type.

Extra

This PR comes with a type-fest break. I already looked through it... so I'll just quote my original answer here:

A distributive homomorphic type requires to be written in this form (roughly):

type M<T> = {
  [K in keyof T]: T[K]
}

A type-fest-based repro case can be seen here. As we can see, that exact form ([K in keyof T]: ...) is used there. Therefore, I think the expectation should be that this would be treated as a distributive homomorphic type.

But because of the issue fixed by this PR, that mapped type was not recognized as homomorphic and distributive. That happened because keyof T in [K in keyof T] became (invisibly!) a substitution type internally. With the fix here, it gets recognized properly~ so it started to distribute and thus it broke type-fest's implementation as it was accidentally leveraging the incorrect behavior.

It's common to change the code a little bit to enable/disable distributivity of conditional types and I think the same principle kinda applied to mapped types, given the distributivity (or the lack of it) is also an implied trait of any mapped type.

I just pushed out a test documenting this and showcasing 2 possible workarounds for the type-fest's case, see this commit. If this PR lands then I will go to type-fest and PR a fix for them.

Copilot AI balanced review requested due to automatic review settings August 20, 2026 10:56
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Aug 20, 2026
@typescript-automation typescript-automation Bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Aug 20, 2026
@typescript-automation

Copy link
Copy Markdown

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes homomorphic mapped-type detection when keyof T is wrapped in a substitution constraint.

Changes:

  • Unwraps substitution constraints before detecting homomorphic mapped types.
  • Adds regression and distributivity tests with baselines.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tsc/internal/checker/checker.go Corrects homomorphism detection.
tsc/testdata/tests/cases/compiler/mappedTypeNotMistakenlyHomomorphic2.ts Tests issue #63132.
tsc/testdata/tests/cases/compiler/mappedTypeHomomorphismWithPriorKeyofTChecks1.ts Tests distributive and non-distributive forms.
tsc/testdata/baselines/reference/compiler/mappedTypeNotMistakenlyHomomorphic2.types Records inferred types.
tsc/testdata/baselines/reference/compiler/mappedTypeNotMistakenlyHomomorphic2.symbols Records symbols.
tsc/testdata/baselines/reference/compiler/mappedTypeHomomorphismWithPriorKeyofTChecks1.types Records distributivity results.
tsc/testdata/baselines/reference/compiler/mappedTypeHomomorphismWithPriorKeyofTChecks1.symbols Records symbols.
tsc/testdata/baselines/reference/compiler/mappedTypeHomomorphismWithPriorKeyofTChecks1.js Records emitted output.

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

Comment thread tsc/testdata/tests/cases/compiler/mappedTypeHomomorphismWithPriorKeyofTChecks1.ts Outdated
@jakebailey

Copy link
Copy Markdown
Member

Can type-fest be changed regardless?

@Andarist

Copy link
Copy Markdown
Contributor Author

Can type-fest be changed regardless?

I think so - yes. It's just that I usually prefer to open followup PRs when relevant TS PRs land. It's easier to explain to other maintainers the issue being fixed is not hypothethical. I'll create that type-fest PR in a moment though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

Regression: Mapped types are no longer homomorphic when wrapped in certain conditional types

4 participants