Skip to content
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

Use missingType in --noUncheckedIndexedAccess mode #51653

Merged
merged 4 commits into from Dec 7, 2022
Merged

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented Nov 27, 2022

This implements what I discuss here. I borrwed tests from that PR. Thanks @Andarist.

Fixes #43614.

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Nov 27, 2022
@ahejlsberg
Copy link
Member Author

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

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 27, 2022

Heya @ahejlsberg, I've started to run the diff-based top-repos suite on this PR at 61104d0. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 27, 2022

Heya @ahejlsberg, I've started to run the diff-based user code test suite on this PR at 61104d0. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 27, 2022

Heya @ahejlsberg, I've started to run the extended test suite on this PR at 61104d0. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 27, 2022

Heya @ahejlsberg, I've started to run the abridged perf test suite on this PR at 61104d0. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 27, 2022

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

@typescript-bot
Copy link
Collaborator

@ahejlsberg Here are the results of running the user test suite comparing main and refs/pull/51653/merge:

Everything looks good!

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - main..51653

Metric main 51653 Delta Best Worst
Angular - node (v16.17.1, x64)
Memory used 340,642k (± 0.01%) 340,607k (± 0.02%) -35k (- 0.01%) 340,403k 340,686k
Parse Time 1.90s (± 0.62%) 1.89s (± 0.73%) -0.02s (- 0.84%) 1.85s 1.92s
Bind Time 0.65s (± 0.51%) 0.65s (± 0.86%) -0.00s (- 0.31%) 0.63s 0.66s
Check Time 5.18s (± 0.51%) 5.17s (± 0.35%) -0.01s (- 0.10%) 5.13s 5.20s
Emit Time 5.13s (± 1.03%) 5.10s (± 0.84%) -0.03s (- 0.60%) 5.00s 5.20s
Total Time 12.87s (± 0.61%) 12.81s (± 0.40%) -0.06s (- 0.44%) 12.69s 12.93s
Compiler-Unions - node (v16.17.1, x64)
Memory used 187,674k (± 0.59%) 187,348k (± 0.51%) -326k (- 0.17%) 186,605k 189,975k
Parse Time 0.79s (± 0.42%) 0.79s (± 0.75%) +0.00s (+ 0.51%) 0.78s 0.81s
Bind Time 0.42s (± 0.53%) 0.42s (± 0.53%) -0.00s (- 0.48%) 0.41s 0.42s
Check Time 6.10s (± 0.89%) 6.10s (± 0.53%) -0.01s (- 0.10%) 6.03s 6.17s
Emit Time 1.94s (± 0.49%) 1.94s (± 0.71%) -0.00s (- 0.05%) 1.90s 1.97s
Total Time 9.25s (± 0.63%) 9.25s (± 0.38%) -0.00s (- 0.02%) 9.17s 9.31s
Monaco - node (v16.17.1, x64)
Memory used 319,814k (± 0.01%) 319,791k (± 0.01%) -23k (- 0.01%) 319,741k 319,867k
Parse Time 1.43s (± 0.35%) 1.42s (± 0.69%) -0.00s (- 0.28%) 1.40s 1.44s
Bind Time 0.59s (± 0.84%) 0.59s (± 0.75%) -0.00s (- 0.50%) 0.58s 0.60s
Check Time 4.90s (± 0.42%) 4.88s (± 0.31%) -0.03s (- 0.53%) 4.84s 4.92s
Emit Time 2.74s (± 0.66%) 2.73s (± 0.59%) -0.01s (- 0.29%) 2.69s 2.77s
Total Time 9.67s (± 0.36%) 9.62s (± 0.25%) -0.04s (- 0.43%) 9.58s 9.68s
TFS - node (v16.17.1, x64)
Memory used 282,278k (± 0.01%) 282,282k (± 0.01%) +5k (+ 0.00%) 282,226k 282,338k
Parse Time 1.17s (± 1.06%) 1.16s (± 1.01%) -0.01s (- 1.02%) 1.14s 1.19s
Bind Time 0.66s (± 3.65%) 0.66s (± 2.84%) +0.00s (+ 0.76%) 0.61s 0.69s
Check Time 4.75s (± 0.51%) 4.76s (± 0.38%) +0.01s (+ 0.27%) 4.70s 4.78s
Emit Time 2.73s (± 2.00%) 2.79s (± 1.99%) +0.07s (+ 2.50%) 2.67s 2.89s
Total Time 9.30s (± 0.88%) 9.38s (± 0.58%) +0.08s (+ 0.81%) 9.26s 9.50s
material-ui - node (v16.17.1, x64)
Memory used 435,275k (± 0.00%) 435,266k (± 0.00%) -9k (- 0.00%) 435,235k 435,297k
Parse Time 1.65s (± 0.41%) 1.65s (± 0.61%) -0.00s (- 0.06%) 1.61s 1.66s
Bind Time 0.50s (± 1.18%) 0.51s (± 0.74%) +0.00s (+ 0.20%) 0.50s 0.51s
Check Time 11.93s (± 0.97%) 11.89s (± 0.74%) -0.04s (- 0.29%) 11.67s 12.04s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 14.08s (± 0.86%) 14.05s (± 0.67%) -0.03s (- 0.23%) 13.83s 14.21s
xstate - node (v16.17.1, x64)
Memory used 515,987k (± 0.01%) 516,086k (± 0.01%) +99k (+ 0.02%) 515,963k 516,236k
Parse Time 2.31s (± 0.53%) 2.31s (± 0.44%) -0.00s (- 0.22%) 2.29s 2.34s
Bind Time 0.83s (± 1.07%) 0.83s (± 1.06%) -0.00s (- 0.48%) 0.82s 0.86s
Check Time 1.37s (± 0.35%) 1.36s (± 0.69%) -0.01s (- 0.51%) 1.34s 1.38s
Emit Time 0.06s (± 0.00%) 0.06s (± 0.00%) 0.00s ( 0.00%) 0.06s 0.06s
Total Time 4.58s (± 0.35%) 4.56s (± 0.42%) -0.01s (- 0.33%) 4.52s 4.62s
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-131-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v16.17.1, x64)
Scenarios
  • Angular - node (v16.17.1, x64)
  • Compiler-Unions - node (v16.17.1, x64)
  • Monaco - node (v16.17.1, x64)
  • TFS - node (v16.17.1, x64)
  • material-ui - node (v16.17.1, x64)
  • xstate - node (v16.17.1, x64)
Benchmark Name Iterations
Current 51653 10
Baseline main 10

Developer Information:

Download Benchmark

@typescript-bot
Copy link
Collaborator

Heya @ahejlsberg, I've run the RWC suite on this PR - assuming you're on the TS core team, you can view the resulting diff here.

@Andarist
Copy link
Contributor

I love it when „in the next day or two” means „in the next half an hour” 😉

else {
obj.test; // undefined
}
}
Copy link
Contributor

@Andarist Andarist Nov 27, 2022

Choose a reason for hiding this comment

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

I've hoped that this solution would make it work (somehow through CFA) for at least the in variant:

function f5(obj: Record<string, string>, prop: string) {
    if (obj[prop]) {
        obj[prop]; // actual: string | undefined; expected: string
    }
    if (prop in obj) {
        obj[prop]; // actual: string | undefined; expected: string
    }
}

Is this kind of analysis supported for any kind of patterns today?

Choose a reason for hiding this comment

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

obj[prop] where prop isn’t a hardcoded literal can’t be narrowed in any way to my knowledge. There are many, many issues attesting to that if you go looking, and it’s considered to be by design.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ye, I've figured out as much - although I wonder how hard a limitation that is.

Choose a reason for hiding this comment

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

Everything gets duped to #10530 which is kind of misleading since that issue was originally about bracketed access with a literal key (which has since been fixed), but the picture that develops after enough hunting is that it’s a performance sinkhole. See e.g. #25109 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

@Andarist It works when prop is declared as a const with a singleton literal type, e.g. const prop = "foo", but no support beyond that. We could conceivably support non-singleton-literal-type const variables, but it isn't trivial.

Copy link

Choose a reason for hiding this comment

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

There are many, many issues attesting to that if you go looking, and it’s considered to be by design.

I understand that this seems difficult to implement and we might never get this feature, but I'm having a hard time understanding how this could be "by design". What I mean is, this seems like fairly straight forward JS and as far as I understand TypeScript's design goals, we really should be able to support (type correctly) this kind of code. I really am sympathetic to the fact that it might not be feasible to do in the current implementation, I'm just challenging the idea that we want it to be this way.

Choose a reason for hiding this comment

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

“By design” = ”intentional decision made during the design process”. Some such decisions are known compromises. I don’t use the phrase to imply it’s what the user wants, because nobody can even define that except for the individual users themselves, and the team can’t go around asking every single user before they’re allowed to label things “working as intended”. 😉

Copy link

Choose a reason for hiding this comment

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

Sure there always needs to be compromises made in the design of the language, but this isn't that. This seems to be a limitation of the current implementation (an implementation detail if you will), not some inherent limitation in the design of the language itself.

Choose a reason for hiding this comment

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

I mean, the implementation is still part of the design of the TypeScript compiler in particular. Obviously a language wouldn't be intentionally designed that way in isolation, but that's a moot point since there's no TypeScript language specification. There used to be a formal spec a long time ago, but nowadays the implementation is the specification, and that's an entirely pragmatic design process. If the implementation is designed a certain way, in practice that means the language is too.

Choose a reason for hiding this comment

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

...at least until someone gets fed up with the limitations and makes an alternative implementation. 😅


function f4(obj: Record<string, string>) {
obj.test; // string | undefined
if (obj.hasOwnProperty("test")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

wow, how does this one work if hasOwnProperty's signature is "just":

hasOwnProperty(v: PropertyKey): boolean;

what kind of sorcery is going on here? :D does this method have some special support in the compiler itself?

Copy link
Member Author

Choose a reason for hiding this comment

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

does this method have some special support in the compiler itself?

It does indeed.

Copy link

Choose a reason for hiding this comment

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

I’m going to assume that feature was implemented early on since nowadays feature requests to special-case built-in methods (like Object.assign) get rejected if the special case can’t be represented in the method signature.

Copy link
Contributor

Choose a reason for hiding this comment

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

For reference, I found the code related to hasOwnProperty here

@typescript-bot
Copy link
Collaborator

@ahejlsberg Here are the results of running the top-repos suite comparing main and refs/pull/51653/merge:

Everything looks good!

@sandersn sandersn added this to Not started in PR Backlog Dec 5, 2022
@sandersn sandersn moved this from Not started to Waiting on reviewers in PR Backlog Dec 5, 2022
@ahejlsberg ahejlsberg merged commit d43112a into main Dec 7, 2022
PR Backlog automation moved this from Waiting on reviewers to Done Dec 7, 2022
@ahejlsberg ahejlsberg deleted the fix43614 branch December 7, 2022 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
PR Backlog
  
Done
Development

Successfully merging this pull request may close these issues.

noUncheckedIndexedAccess does not narrow properly with "prop" in obj
6 participants