Narrow on element access of known property#10565
Conversation
Narrowing now happens for x['knownProperty'] as well as x.knownProperty
|
@RyanCavanaugh @ahejlsberg do you want to take a look? |
src/compiler/binder.ts
Outdated
| expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression); | ||
| if (expr.kind === SyntaxKind.ElementAccessExpression) { | ||
| const argument = (expr as ElementAccessExpression).argumentExpression; | ||
| return argument.kind === SyntaxKind.StringLiteral || argument.kind === SyntaxKind.NumericLiteral || argument.kind === SyntaxKind.EnumMember; |
There was a problem hiding this comment.
the expr.expression should be, an identifier, this, a PopertyAccessExpression or ElementAccessExpression , so we should recursively call the function on the expression.
There was a problem hiding this comment.
we should also add tests to multiple levels of elementAccess. a[0][1]
There was a problem hiding this comment.
Actually, multiple levels of property access don't work either. So I think this function should actually be even simpler until we fix that bug.
interface Square {
sub: { kind: "square; };
size: number;
}
// etc ...
function area(s: Shape) {
switch(s.sub.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.width * s.height;
case "circle": return Math.PI * s.radius * s.radius;
}
}|
Nested element accesses are now supported. |
|
@mhegazy you started reviewing this change. Can you look at the new commits so it can go in? |
|
I ran a performance benchmark on the code compared to master. The standout difference was that Monaco (the online component that powers the playground) has a 6.85% slowdown in the checker, or 0.41 second. TFS has a small slowdown in the checker but it's not statistically significant. I'm trying to get github formatting to co-operate so I can show the actual table but haven't had any luck yet. |
|
As @mhegazy suggested, I tried the benchmark again, this time only narrowing string element accesses, not number accesses. The results are about the same. |
|
given the performance penalty vs. utility of this change, we will not be able to take it. |
|
Would it be possible to revise the decision on this PR 1.5 years since the original implementation? Will the performance impact be so critical now too? When a property has spaces or other no-standard characters, it is impossible to either define it or read its value via const config = {
param: 42,
"param 2": 43,
}
console.log(config.parammmmm); // <--- typo caught by the compiler
console.log(config["parammmmm 2"]); // <--- typo not caught |
|
i do not think the error you listed above has do with this PR. The issue here is that it is legal to index into any property using a string/numeric name. the result is an implicit |
|
I'm not sure that |
|
could this perhaps land behind a flag? or maybe just for numeric properties accessed via brackets? |
|
I reconstituted the PR and found (1) a probably performance bug that it introduced in |
|
Can we have this behind a flag? I've had to add dozens of non-null assertions to fix this and would gladly take the 6.5% performance hit. |
|
I agree, the current behavior is unintuitive and should be fixed. |
|
For what it's worth, I've verified that For my use case, It's purported that #10530 is tracking the issue and #48335 is tracking new documentation for the current behavior and workarounds. |
|
Would it be possible for us to simply rebase this branch and rerun the benchmarks to get a clearer picture of the real-world performance? |
|
@sandersn, what do you think about the above question? Could we give this another try, please? |
|
One does not "simply" rebase a 7-year-old PR 😅 The example in the linked issue, and the example in this comment #10565 (comment), both now work. Can you clarify what you're looking for? |
|
Now as I am reading the purpose of this PR again, I certainly commented on the wrong one. I was trying to figure out why TS doesn't narrow down the type in this specific scenario. |
Fixes #10530
Narrowing now happens for
x['knownProperty']the same way that it does forx.knownProperty