Skip to content

Fix excess property checking for unions with index signatures #34927

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 5 commits into from
Nov 15, 2019

Conversation

ahejlsberg
Copy link
Member

This PR revises our excess property checking logic to properly handle union types with index signatures. For example, both of the following now error where previously they didn't:

const obj1: { [x: string]: number } | { [x: number]: number } = { a: 'abc' };  // Error
const obj2: { [x: string]: number } | { a: number } = { a: 5, c: 'abc' };  // Error

Fixes #34611.

@ahejlsberg
Copy link
Member Author

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 5, 2019

Heya @ahejlsberg, I've started to run the extended test suite on this PR at 386e550. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 5, 2019

Heya @ahejlsberg, I've started to run the perf test suite on this PR at 386e550. You can monitor the build here. It should now contribute to this PR's status checks.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 5, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 386e550. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - master..34927

Metric master 34927 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 355,187k (± 0.03%) 356,380k (± 0.02%) +1,194k (+ 0.34%) 356,196k 356,476k
Parse Time 1.62s (± 0.64%) 1.63s (± 0.51%) +0.01s (+ 0.80%) 1.61s 1.65s
Bind Time 0.86s (± 0.55%) 0.87s (± 0.89%) +0.01s (+ 1.05%) 0.85s 0.89s
Check Time 4.54s (± 0.43%) 4.52s (± 0.50%) -0.02s (- 0.48%) 4.46s 4.58s
Emit Time 5.26s (± 0.81%) 5.28s (± 0.80%) +0.01s (+ 0.25%) 5.22s 5.40s
Total Time 12.29s (± 0.53%) 12.30s (± 0.43%) +0.01s (+ 0.10%) 12.20s 12.46s
Monaco - node (v10.16.3, x64)
Memory used 365,972k (± 0.02%) 365,923k (± 0.01%) -49k (- 0.01%) 365,830k 366,031k
Parse Time 1.26s (± 0.44%) 1.26s (± 0.46%) -0.00s (- 0.16%) 1.25s 1.27s
Bind Time 0.76s (± 0.45%) 0.75s (± 0.63%) -0.01s (- 0.92%) 0.74s 0.76s
Check Time 4.66s (± 0.30%) 4.63s (± 0.33%) -0.03s (- 0.66%) 4.58s 4.65s
Emit Time 2.95s (± 0.87%) 2.95s (± 0.69%) +0.00s (+ 0.03%) 2.90s 2.98s
Total Time 9.63s (± 0.36%) 9.59s (± 0.21%) -0.04s (- 0.40%) 9.56s 9.65s
TFS - node (v10.16.3, x64)
Memory used 321,649k (± 0.02%) 321,710k (± 0.02%) +62k (+ 0.02%) 321,580k 321,937k
Parse Time 0.96s (± 0.35%) 0.95s (± 0.59%) -0.01s (- 1.25%) 0.94s 0.96s
Bind Time 0.72s (± 1.78%) 0.73s (± 0.61%) +0.01s (+ 1.39%) 0.72s 0.74s
Check Time 4.11s (± 0.56%) 4.10s (± 0.58%) -0.01s (- 0.17%) 4.05s 4.16s
Emit Time 3.06s (± 1.04%) 3.05s (± 0.98%) -0.01s (- 0.33%) 2.98s 3.11s
Total Time 8.84s (± 0.48%) 8.82s (± 0.56%) -0.02s (- 0.25%) 8.71s 8.93s
Angular - node (v12.1.0, x64)
Memory used 330,684k (± 0.05%) 331,777k (± 0.08%) +1,093k (+ 0.33%) 331,013k 332,075k
Parse Time 1.57s (± 0.85%) 1.58s (± 0.52%) +0.01s (+ 0.76%) 1.57s 1.61s
Bind Time 0.85s (± 1.42%) 0.86s (± 0.95%) +0.01s (+ 1.18%) 0.84s 0.88s
Check Time 4.44s (± 0.65%) 4.45s (± 0.68%) +0.01s (+ 0.27%) 4.38s 4.52s
Emit Time 5.46s (± 0.87%) 5.50s (± 1.12%) +0.04s (+ 0.66%) 5.42s 5.67s
Total Time 12.33s (± 0.39%) 12.39s (± 0.73%) +0.07s (+ 0.54%) 12.25s 12.62s
Monaco - node (v12.1.0, x64)
Memory used 345,728k (± 0.02%) 345,702k (± 0.02%) -26k (- 0.01%) 345,500k 345,822k
Parse Time 1.23s (± 0.56%) 1.23s (± 0.56%) +0.00s (+ 0.08%) 1.21s 1.24s
Bind Time 0.72s (± 0.94%) 0.73s (± 0.61%) +0.00s (+ 0.41%) 0.72s 0.74s
Check Time 4.48s (± 0.29%) 4.48s (± 0.44%) +0.00s (+ 0.02%) 4.42s 4.53s
Emit Time 2.99s (± 0.74%) 3.03s (± 1.06%) +0.04s (+ 1.17%) 2.98s 3.14s
Total Time 9.42s (± 0.32%) 9.46s (± 0.47%) +0.04s (+ 0.41%) 9.34s 9.57s
TFS - node (v12.1.0, x64)
Memory used 304,025k (± 0.01%) 304,057k (± 0.01%) +32k (+ 0.01%) 303,964k 304,141k
Parse Time 0.95s (± 0.59%) 0.95s (± 0.68%) +0.00s (+ 0.00%) 0.93s 0.96s
Bind Time 0.69s (± 1.35%) 0.68s (± 0.54%) -0.00s (- 0.44%) 0.68s 0.69s
Check Time 4.04s (± 0.44%) 4.04s (± 0.71%) -0.00s (- 0.10%) 3.98s 4.10s
Emit Time 3.11s (± 1.16%) 3.12s (± 1.59%) +0.01s (+ 0.35%) 3.06s 3.30s
Total Time 8.79s (± 0.42%) 8.79s (± 0.70%) +0.00s (+ 0.03%) 8.71s 9.01s
Angular - node (v8.9.0, x64)
Memory used 349,911k (± 0.02%) 351,156k (± 0.03%) +1,245k (+ 0.36%) 350,891k 351,332k
Parse Time 2.11s (± 0.80%) 2.11s (± 0.55%) +0.00s (+ 0.09%) 2.09s 2.14s
Bind Time 0.90s (± 0.54%) 0.91s (± 0.83%) +0.01s (+ 1.11%) 0.90s 0.94s
Check Time 5.29s (± 0.78%) 5.25s (± 0.84%) -0.04s (- 0.66%) 5.16s 5.35s
Emit Time 6.25s (± 1.68%) 6.21s (± 1.24%) -0.04s (- 0.66%) 6.05s 6.41s
Total Time 14.56s (± 0.96%) 14.49s (± 0.61%) -0.07s (- 0.46%) 14.33s 14.73s
Monaco - node (v8.9.0, x64)
Memory used 363,812k (± 0.01%) 363,726k (± 0.01%) -85k (- 0.02%) 363,643k 363,813k
Parse Time 1.56s (± 0.64%) 1.56s (± 0.48%) 0.00s ( 0.00%) 1.54s 1.57s
Bind Time 0.92s (± 0.81%) 0.92s (± 0.76%) -0.00s (- 0.11%) 0.91s 0.94s
Check Time 5.51s (± 0.39%) 5.53s (± 0.94%) +0.02s (+ 0.40%) 5.43s 5.64s
Emit Time 3.03s (± 0.47%) 3.06s (± 0.69%) +0.03s (+ 0.96%) 3.04s 3.14s
Total Time 11.02s (± 0.25%) 11.07s (± 0.57%) +0.05s (+ 0.44%) 10.96s 11.22s
TFS - node (v8.9.0, x64)
Memory used 320,589k (± 0.01%) 320,569k (± 0.02%) -20k (- 0.01%) 320,393k 320,744k
Parse Time 1.27s (± 0.37%) 1.27s (± 0.49%) -0.00s (- 0.31%) 1.26s 1.28s
Bind Time 0.74s (± 0.78%) 0.74s (± 1.00%) -0.00s (- 0.40%) 0.73s 0.76s
Check Time 4.72s (± 0.62%) 4.72s (± 0.47%) +0.00s (+ 0.06%) 4.68s 4.77s
Emit Time 3.22s (± 0.72%) 3.22s (± 0.53%) -0.00s (- 0.16%) 3.16s 3.25s
Total Time 9.96s (± 0.52%) 9.95s (± 0.17%) -0.01s (- 0.11%) 9.90s 9.98s
Angular - node (v8.9.0, x86)
Memory used 198,688k (± 0.01%) 199,283k (± 0.02%) +595k (+ 0.30%) 199,224k 199,377k
Parse Time 2.04s (± 0.95%) 2.04s (± 0.59%) +0.01s (+ 0.29%) 2.01s 2.06s
Bind Time 1.03s (± 0.63%) 1.01s (± 0.49%) -0.02s (- 1.65%) 1.00s 1.02s
Check Time 4.81s (± 0.37%) 4.78s (± 0.48%) -0.03s (- 0.54%) 4.74s 4.85s
Emit Time 6.03s (± 0.59%) 6.06s (± 2.08%) +0.02s (+ 0.38%) 5.75s 6.33s
Total Time 13.91s (± 0.40%) 13.90s (± 1.00%) -0.02s (- 0.12%) 13.65s 14.22s
Monaco - node (v8.9.0, x86)
Memory used 203,806k (± 0.02%) 203,733k (± 0.02%) -73k (- 0.04%) 203,678k 203,865k
Parse Time 1.61s (± 0.73%) 1.61s (± 0.71%) +0.00s (+ 0.06%) 1.59s 1.64s
Bind Time 0.75s (± 0.60%) 0.75s (± 0.64%) -0.00s (- 0.13%) 0.74s 0.76s
Check Time 5.38s (± 0.33%) 5.39s (± 1.13%) +0.01s (+ 0.15%) 5.17s 5.47s
Emit Time 2.86s (± 0.71%) 2.89s (± 2.47%) +0.02s (+ 0.87%) 2.83s 3.17s
Total Time 10.60s (± 0.29%) 10.63s (± 0.38%) +0.04s (+ 0.34%) 10.53s 10.71s
TFS - node (v8.9.0, x86)
Memory used 180,608k (± 0.03%) 180,580k (± 0.02%) -28k (- 0.02%) 180,472k 180,639k
Parse Time 1.31s (± 0.64%) 1.31s (± 0.52%) 0.00s ( 0.00%) 1.30s 1.33s
Bind Time 0.69s (± 0.52%) 0.70s (± 0.71%) +0.00s (+ 0.29%) 0.69s 0.71s
Check Time 4.46s (± 0.37%) 4.47s (± 0.44%) +0.01s (+ 0.20%) 4.42s 4.52s
Emit Time 3.00s (± 1.29%) 2.96s (± 1.18%) -0.04s (- 1.47%) 2.87s 3.03s
Total Time 9.46s (± 0.53%) 9.43s (± 0.45%) -0.03s (- 0.36%) 9.31s 9.49s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-166-generic
Architecturex64
Available Memory16 GB
Available Memory8 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
Benchmark Name Iterations
Current 34927 10
Baseline master 10

@ahejlsberg
Copy link
Member Author

Performance is unaffected, so we're fine there. RWC tests have a few error elaboration changes, but they look fine.

DT tests reveal genuine errors in the tests of three packages, xml, mergerino, and styled-system__css, that apparently were masked by our old excess property checking logic.

Copy link
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

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

I mentioned it in-person, but here's my notes~

!!! error TS2200: The types of 'icon.props' are incompatible between these types.
!!! error TS2200: Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'.
!!! error TS2200: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'.
!!! error TS2345: Argument of type '{ icon: { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }; }' is not assignable to parameter of type '(TestProps & { children?: number; }) | ({ props2: { x: number; }; } & { children?: number; })'.
Copy link
Member

@weswigham weswigham Nov 6, 2019

Choose a reason for hiding this comment

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

Should we try and keep this line of elaboration suppressed? I think the filtering we were doing before had the effect of suppressing it.

type Thing3 = number | { toFixed: null, toString: undefined } | object;
const l: Thing3 = { toString: undefined }; // error, toFixed isn't null
~
!!! error TS2741: Property 'toFixed' is missing in type '{ toString: undefined; }' but required in type '{ toFixed: null; toString: undefined; }'.
Copy link
Member

Choose a reason for hiding this comment

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

IMO, this should still be an error - #31708 came up because we unconditionally treated object as a type with no properties for excess property checking (so all usages of object used to trigger excess property errors like this), which caused problems in these primitive only unions (where there really isn't any hinting as to what properties an object literal should contain, really), however in case like this one, where there's an explicit object type, using the hints from the specified object types for excess properties is more desirable (and prevents you form passing total garbage and typo'ing the property names from the provided literal).

Copy link
Member Author

Choose a reason for hiding this comment

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

This PR doesn't change anything with respect to #31708. That logic is still in place and we still filter out primitives from unions containing object before we do excess property checking. Also, there was never any logic in place to remove object when actual object types are present. Rather, when object is present in a union it effectively turns off excess property checking, just like {}. However, we had some very odd behavior when it came to using toString and the other property names from Object. For example:

let x1: { a: string, b: number } | object = { a: 'test' };
let x2: { a: 'test', b: number } | object = { a: 'test' };
let x3: { toString: string, b: number } | object = { toString: 'test' };
let x4: { toString: 'test', b: number } | object = { toString: 'test' };  // Error!

Above, we would error on x4, but not on any of the other ones. That just doesn't make sense, and we now permit it. (Keep in mind here that by design we don't give special treatment to toString and the other Object properties in assignment checking.)

Copy link
Member

Choose a reason for hiding this comment

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

As I said in person - {} disables excess property checking because it has baggage whereupon it was used as a general top type. object has no such compunctions. Otherwise there's no way to have an excess property checked empty object.

Copy link
Member Author

Choose a reason for hiding this comment

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

What I'm pointing out is that, except for the logic that filters out primitives, object and {} behave the same for purposes of excess property checking in the current compiler. It's existing behavior and unrelated to the issue I'm fixing in this PR.

@ahejlsberg ahejlsberg added the Breaking Change Would introduce errors in existing code label Nov 15, 2019
@ahejlsberg
Copy link
Member Author

Adding the Breaking Change label since we now catch more issues.

@ahejlsberg ahejlsberg merged commit 196c0aa into master Nov 15, 2019
@ahejlsberg ahejlsberg deleted the fix34611 branch November 15, 2019 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Would introduce errors in existing code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Type checking does not works for indexable type with number keys OR string keys
4 participants