Skip to content

Allow type comparison when target is generic mapped type with key remapping #45700

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 8, 2021

Conversation

gabritto
Copy link
Member

@gabritto gabritto commented Sep 3, 2021

Fixes #45212

@typescript-bot typescript-bot added the For Milestone Bug PRs that fix a bug with a specific milestone label Sep 3, 2021
// If the target type has shape `{ [P in Q as R]: T }`, then a property of the target has type `R`.
// If the target type has shape `{ [P in Q as R]?: T }`, then a property of the target has type `R`,
// but the property is optional, so we only want to compare properties `R` that are common between `keyof S` and `R`.
const indexingType = keysRemapped
Copy link
Member Author

Choose a reason for hiding this comment

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

I am not entirely sure this won't cause issues for the case where the target mapped type has an include optional modifier.

Copy link
Member

Choose a reason for hiding this comment

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

So, to be clear here, in the keysRemapped case, we're skipping the getIntersectionType calls with the typeParameter, simply because the keys may or may not actually contain the remapping type parameter (eg, every key may just be mapped to string) - the targetKeys will already contain it if so. I think this is correct - it's just not necessarily clear. In the case where there's no as clause, we intersect the type parameter and the (filtered) keys so we get a generic property key - whereas when the keys are remapped, we don't need to do so as the remapping overrides that.

@andrewbranch
Copy link
Member

@typescript-bot perf test this
@typescript-bot user test this inline
@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 3, 2021

Heya @andrewbranch, I'm starting to run the inline community code test suite on this PR at ca98987. Hold tight - I'll update this comment with the log link once the build has been queued.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 3, 2021

Heya @andrewbranch, I've started to run the parallelized Definitely Typed test suite on this PR at ca98987. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 3, 2021

Heya @andrewbranch, I've started to run the perf test suite on this PR at ca98987. You can monitor the build here.

Update: The results are in!


function fun2<T>(val: T) {
let x: FilterInclOpt<T> = val; // Ok
let y: ModifyInclOpt<T> = val; // Ok
Copy link
Member

@andrewbranch andrewbranch Sep 3, 2021

Choose a reason for hiding this comment

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

My initial reaction to this one was that this is wrong because T might have some property that would conflict with the remapped property type, e.g. if T was instantiated with { foo: string, boolfoo: number }. However, it looks like that’s an unsoundness that already exists independent of mapped types entirely:

interface Foo {
    x?: string;
    y?: string;
    z?: string;
}

function f<T>(x: T) { // What if `T` is `{ x: number }`?
    const _: Foo = x;
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I tried to follow the already existing logic and reuse everything that's already there, so there might be inconsistencies that were already there or that result from the kind of types that are in key remapping clauses.

Copy link
Member

Choose a reason for hiding this comment

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

Optional properties are a pretty big soundness hole, unfortunately. The unconstrained generic one is actually one I have a PR up to remove - #33570

Copy link
Contributor

Choose a reason for hiding this comment

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

This exact discussed case has changed behavior in 51b346d#diff-25f367dc11e40edc9febb9d6f088e13f9c7c8086bb8b9f85aed321f0903bc46eR31-R33

One of my PRs bring back original behavior (somewhat accidentally, I wasn't aiming for it), see here

Which one is correct? 😅

@typescript-bot
Copy link
Collaborator

@andrewbranch
Great news! no new errors were found between main..refs/pull/45700/merge

@typescript-bot
Copy link
Collaborator

@andrewbranch
The results of the perf run you requested are in!

Here they are:

Comparison Report - main..45700

Metric main 45700 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 351,611k (± 0.03%) 351,494k (± 0.01%) -117k (- 0.03%) 351,420k 351,584k
Parse Time 1.91s (± 0.30%) 1.90s (± 0.50%) -0.01s (- 0.52%) 1.87s 1.92s
Bind Time 0.85s (± 0.40%) 0.86s (± 0.82%) +0.01s (+ 0.70%) 0.85s 0.88s
Check Time 5.39s (± 0.41%) 5.38s (± 0.43%) -0.01s (- 0.09%) 5.35s 5.45s
Emit Time 5.83s (± 0.42%) 5.82s (± 0.32%) -0.00s (- 0.09%) 5.79s 5.85s
Total Time 13.97s (± 0.25%) 13.96s (± 0.27%) -0.01s (- 0.10%) 13.88s 14.08s
Compiler-Unions - node (v10.16.3, x64)
Memory used 203,474k (± 0.03%) 203,485k (± 0.03%) +11k (+ 0.01%) 203,380k 203,661k
Parse Time 0.78s (± 0.85%) 0.78s (± 0.57%) +0.00s (+ 0.26%) 0.77s 0.79s
Bind Time 0.52s (± 1.13%) 0.52s (± 0.90%) -0.00s (- 0.76%) 0.51s 0.53s
Check Time 7.82s (± 0.42%) 7.81s (± 0.42%) -0.01s (- 0.14%) 7.73s 7.86s
Emit Time 2.44s (± 0.51%) 2.43s (± 1.05%) -0.01s (- 0.45%) 2.38s 2.49s
Total Time 11.56s (± 0.42%) 11.54s (± 0.30%) -0.02s (- 0.17%) 11.46s 11.64s
Monaco - node (v10.16.3, x64)
Memory used 340,659k (± 0.02%) 340,591k (± 0.01%) -68k (- 0.02%) 340,489k 340,715k
Parse Time 1.45s (± 0.69%) 1.45s (± 0.95%) -0.00s (- 0.21%) 1.40s 1.47s
Bind Time 0.75s (± 0.87%) 0.75s (± 0.97%) 0.00s ( 0.00%) 0.73s 0.76s
Check Time 5.44s (± 0.37%) 5.41s (± 0.40%) -0.03s (- 0.61%) 5.36s 5.45s
Emit Time 3.17s (± 0.78%) 3.17s (± 1.03%) +0.00s (+ 0.03%) 3.12s 3.28s
Total Time 10.80s (± 0.32%) 10.77s (± 0.32%) -0.03s (- 0.30%) 10.70s 10.85s
TFS - node (v10.16.3, x64)
Memory used 304,028k (± 0.01%) 304,026k (± 0.02%) -2k (- 0.00%) 303,917k 304,143k
Parse Time 1.18s (± 0.52%) 1.18s (± 0.69%) +0.00s (+ 0.08%) 1.16s 1.20s
Bind Time 0.72s (± 0.95%) 0.71s (± 0.95%) -0.00s (- 0.28%) 0.69s 0.72s
Check Time 4.92s (± 0.56%) 4.92s (± 0.63%) +0.01s (+ 0.14%) 4.87s 5.02s
Emit Time 3.31s (± 1.05%) 3.29s (± 1.10%) -0.02s (- 0.57%) 3.19s 3.39s
Total Time 10.12s (± 0.45%) 10.11s (± 0.46%) -0.02s (- 0.18%) 9.98s 10.20s
material-ui - node (v10.16.3, x64)
Memory used 469,942k (± 0.01%) 469,912k (± 0.01%) -30k (- 0.01%) 469,730k 470,008k
Parse Time 1.73s (± 0.40%) 1.73s (± 0.42%) +0.00s (+ 0.17%) 1.71s 1.74s
Bind Time 0.66s (± 0.55%) 0.67s (± 1.20%) +0.00s (+ 0.60%) 0.65s 0.69s
Check Time 14.15s (± 0.27%) 14.14s (± 0.42%) -0.01s (- 0.04%) 14.05s 14.27s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 16.54s (± 0.24%) 16.54s (± 0.38%) +0.00s (+ 0.01%) 16.44s 16.68s
Angular - node (v12.1.0, x64)
Memory used 329,584k (± 0.03%) 329,578k (± 0.02%) -6k (- 0.00%) 329,395k 329,702k
Parse Time 1.88s (± 0.62%) 1.88s (± 0.63%) -0.00s (- 0.05%) 1.85s 1.90s
Bind Time 0.83s (± 0.44%) 0.84s (± 0.79%) +0.01s (+ 0.96%) 0.83s 0.86s
Check Time 5.22s (± 0.52%) 5.23s (± 0.35%) +0.01s (+ 0.17%) 5.18s 5.26s
Emit Time 6.05s (± 0.49%) 6.13s (± 0.61%) +0.07s (+ 1.21%) 6.01s 6.19s
Total Time 13.98s (± 0.31%) 14.07s (± 0.35%) +0.09s (+ 0.63%) 13.97s 14.16s
Compiler-Unions - node (v12.1.0, x64)
Memory used 191,013k (± 0.02%) 191,031k (± 0.02%) +18k (+ 0.01%) 190,931k 191,125k
Parse Time 0.78s (± 0.83%) 0.78s (± 0.43%) +0.00s (+ 0.13%) 0.78s 0.79s
Bind Time 0.52s (± 1.13%) 0.53s (± 0.94%) +0.00s (+ 0.38%) 0.52s 0.54s
Check Time 7.37s (± 0.58%) 7.37s (± 0.52%) -0.01s (- 0.07%) 7.30s 7.47s
Emit Time 2.47s (± 1.18%) 2.46s (± 1.06%) -0.01s (- 0.28%) 2.40s 2.54s
Total Time 11.15s (± 0.49%) 11.14s (± 0.24%) -0.01s (- 0.12%) 11.09s 11.20s
Monaco - node (v12.1.0, x64)
Memory used 323,734k (± 0.01%) 323,734k (± 0.02%) -1k (- 0.00%) 323,630k 323,882k
Parse Time 1.43s (± 0.51%) 1.42s (± 0.52%) -0.01s (- 0.56%) 1.40s 1.43s
Bind Time 0.72s (± 0.47%) 0.73s (± 0.94%) +0.00s (+ 0.41%) 0.71s 0.74s
Check Time 5.26s (± 0.43%) 5.25s (± 0.64%) -0.01s (- 0.10%) 5.19s 5.35s
Emit Time 3.19s (± 0.67%) 3.19s (± 0.71%) -0.00s (- 0.06%) 3.14s 3.24s
Total Time 10.60s (± 0.35%) 10.58s (± 0.44%) -0.01s (- 0.11%) 10.48s 10.70s
TFS - node (v12.1.0, x64)
Memory used 288,714k (± 0.02%) 288,743k (± 0.02%) +29k (+ 0.01%) 288,596k 288,865k
Parse Time 1.20s (± 0.77%) 1.21s (± 0.58%) +0.01s (+ 0.58%) 1.20s 1.23s
Bind Time 0.70s (± 0.71%) 0.70s (± 0.88%) +0.00s (+ 0.43%) 0.68s 0.71s
Check Time 4.83s (± 0.41%) 4.87s (± 0.61%) +0.04s (+ 0.85%) 4.80s 4.94s
Emit Time 3.37s (± 0.55%) 3.38s (± 0.48%) +0.00s (+ 0.09%) 3.34s 3.42s
Total Time 10.10s (± 0.32%) 10.15s (± 0.35%) +0.05s (+ 0.52%) 10.06s 10.22s
material-ui - node (v12.1.0, x64)
Memory used 448,462k (± 0.07%) 448,255k (± 0.09%) -207k (- 0.05%) 447,444k 448,819k
Parse Time 1.72s (± 0.47%) 1.73s (± 0.54%) +0.00s (+ 0.29%) 1.71s 1.76s
Bind Time 0.65s (± 0.86%) 0.65s (± 0.56%) +0.01s (+ 0.93%) 0.65s 0.66s
Check Time 12.78s (± 0.53%) 12.90s (± 0.99%) +0.11s (+ 0.88%) 12.67s 13.24s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.15s (± 0.46%) 15.28s (± 0.85%) +0.12s (+ 0.81%) 15.05s 15.64s
Angular - node (v14.15.1, x64)
Memory used 328,115k (± 0.01%) 328,104k (± 0.01%) -11k (- 0.00%) 328,046k 328,182k
Parse Time 1.91s (± 0.70%) 1.89s (± 0.33%) -0.02s (- 0.94%) 1.88s 1.90s
Bind Time 0.88s (± 1.13%) 0.88s (± 1.02%) -0.00s (- 0.57%) 0.87s 0.91s
Check Time 5.29s (± 0.46%) 5.28s (± 0.66%) -0.01s (- 0.17%) 5.18s 5.36s
Emit Time 6.22s (± 0.87%) 6.17s (± 0.45%) -0.05s (- 0.85%) 6.10s 6.24s
Total Time 14.30s (± 0.55%) 14.21s (± 0.39%) -0.09s (- 0.62%) 14.08s 14.32s
Compiler-Unions - node (v14.15.1, x64)
Memory used 192,165k (± 0.48%) 191,203k (± 0.62%) -962k (- 0.50%) 189,567k 192,851k
Parse Time 0.81s (± 0.76%) 0.81s (± 0.64%) +0.00s (+ 0.25%) 0.80s 0.82s
Bind Time 0.55s (± 1.08%) 0.55s (± 0.81%) -0.00s (- 0.54%) 0.54s 0.56s
Check Time 7.50s (± 0.50%) 7.50s (± 0.45%) -0.01s (- 0.08%) 7.44s 7.58s
Emit Time 2.45s (± 0.58%) 2.45s (± 1.02%) -0.00s (- 0.08%) 2.40s 2.51s
Total Time 11.31s (± 0.44%) 11.31s (± 0.43%) -0.01s (- 0.07%) 11.21s 11.44s
Monaco - node (v14.15.1, x64)
Memory used 322,544k (± 0.00%) 322,545k (± 0.00%) +0k (+ 0.00%) 322,525k 322,562k
Parse Time 1.49s (± 0.98%) 1.48s (± 0.46%) -0.00s (- 0.07%) 1.47s 1.50s
Bind Time 0.75s (± 0.40%) 0.76s (± 0.90%) +0.00s (+ 0.53%) 0.75s 0.78s
Check Time 5.21s (± 0.61%) 5.24s (± 0.39%) +0.02s (+ 0.44%) 5.19s 5.30s
Emit Time 3.22s (± 0.63%) 3.23s (± 0.56%) +0.01s (+ 0.40%) 3.19s 3.27s
Total Time 10.67s (± 0.46%) 10.71s (± 0.19%) +0.04s (+ 0.37%) 10.67s 10.75s
TFS - node (v14.15.1, x64)
Memory used 287,699k (± 0.01%) 287,701k (± 0.00%) +2k (+ 0.00%) 287,677k 287,728k
Parse Time 1.26s (± 1.13%) 1.26s (± 1.99%) +0.01s (+ 0.64%) 1.20s 1.33s
Bind Time 0.72s (± 0.80%) 0.72s (± 0.80%) -0.00s (- 0.00%) 0.71s 0.74s
Check Time 4.86s (± 0.54%) 4.88s (± 0.38%) +0.02s (+ 0.49%) 4.85s 4.93s
Emit Time 3.46s (± 1.01%) 3.45s (± 0.54%) -0.01s (- 0.38%) 3.42s 3.51s
Total Time 10.30s (± 0.40%) 10.32s (± 0.44%) +0.02s (+ 0.19%) 10.22s 10.43s
material-ui - node (v14.15.1, x64)
Memory used 447,023k (± 0.00%) 447,008k (± 0.00%) -15k (- 0.00%) 446,980k 447,073k
Parse Time 1.76s (± 0.47%) 1.76s (± 0.41%) +0.00s (+ 0.11%) 1.74s 1.77s
Bind Time 0.68s (± 0.87%) 0.69s (± 0.53%) +0.00s (+ 0.15%) 0.68s 0.69s
Check Time 12.90s (± 0.53%) 12.90s (± 0.35%) +0.01s (+ 0.07%) 12.83s 13.00s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.34s (± 0.50%) 15.35s (± 0.28%) +0.01s (+ 0.08%) 15.28s 15.45s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-210-generic
Architecturex64
Available Memory16 GB
Available Memory9 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v14.15.1, x64)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v14.15.1, x64)
  • Compiler-Unions - node (v10.16.3, x64)
  • Compiler-Unions - node (v12.1.0, x64)
  • Compiler-Unions - node (v14.15.1, x64)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v14.15.1, x64)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v14.15.1, x64)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v14.15.1, x64)
Benchmark Name Iterations
Current 45700 10
Baseline main 10

Developer Information:

Download Benchmark

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

Overall looks correct to me, although I'm not fluent with this code anymore.
One small formatting suggestion.

Comment on lines +18635 to +18639
const indexingType = keysRemapped
? (filteredByApplicability || targetKeys)
: filteredByApplicability
? getIntersectionType([filteredByApplicability, typeParameter])
: typeParameter;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const indexingType = keysRemapped
? (filteredByApplicability || targetKeys)
: filteredByApplicability
? getIntersectionType([filteredByApplicability, typeParameter])
: typeParameter;
const indexingType = keysRemapped ? (filteredByApplicability || targetKeys)
: filteredByApplicability ? getIntersectionType([filteredByApplicability, typeParameter])
: typeParameter;

// If the target type has shape `{ [P in Q as R]: T }`, then a property of the target has type `R`.
// If the target type has shape `{ [P in Q as R]?: T }`, then a property of the target has type `R`,
// but the property is optional, so we only want to compare properties `R` that are common between `keyof S` and `R`.
const indexingType = keysRemapped
Copy link
Member

Choose a reason for hiding this comment

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

So, to be clear here, in the keysRemapped case, we're skipping the getIntersectionType calls with the typeParameter, simply because the keys may or may not actually contain the remapping type parameter (eg, every key may just be mapped to string) - the targetKeys will already contain it if so. I think this is correct - it's just not necessarily clear. In the case where there's no as clause, we intersect the type parameter and the (filtered) keys so we get a generic property key - whereas when the keys are remapped, we don't need to do so as the remapping overrides that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Milestone Bug PRs that fix a bug with a specific milestone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ts2536 thrown when use key remapping to filter out some keys
6 participants