Skip to content

Improve best type matching for elementwise elaborations - #57537

Closed
Mateusz Burzyński (Andarist) wants to merge 10 commits into
microsoft:mainfrom
Andarist:fix/elementwise-errors-best-type-obj-literal
Closed

Improve best type matching for elementwise elaborations#57537
Mateusz Burzyński (Andarist) wants to merge 10 commits into
microsoft:mainfrom
Andarist:fix/elementwise-errors-best-type-obj-literal

Conversation

@Andarist

@AndaristMateusz Burzyński (Andarist) commented Feb 25, 2024

Copy link
Copy Markdown
Contributor

fixes#57541

This PR improves error locations for elementwise error elaborations in a couple of situations. It often finds a better property candidate for the printed error - so the highlighted error is way closer to the actual problem, and it's easier to focus on it. At times, when finding a candidate property when previously it couldn't find any, it also reduces the error span - which is also less distracting.

@Andarist
Mateusz Burzyński (Andarist) marked this pull request as ready for review February 26, 2024 07:22
@typescript-botTypeScript Bot (typescript-bot) added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Feb 26, 2024
if (idx) {
return idx;
}
if (target.flags & TypeFlags.Union) {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

swapping the order of operations here improves some errors quite a bit in my eyes since the union discrimination happens early, for example:

constobj6: {prop:
|{type: "foo";prop: string;}|{type: "bar";prop: number;};}={prop: {type: "foo",// current: Type 'boolean' is not assignable to type 'string | number'.// pr: Type 'boolean' is not assignable to type 'string'prop: true,},};constobj7: {prop:
|{type: "foo";prop: string;}|{type: "bar";prop: number;};}={// current: Type '{ type: "foo"; prop: number; }' is not assignable to type '{ type: "foo"; prop: string; } | { type: "bar"; prop: number; }'.// Types of property 'prop' are incompatible.// Type 'number' is not assignable to type 'string'.prop: {type: "foo",// pr: Type 'number' is not assignable to type 'string'.prop: 42,},};

}
}
if (reportErrors) {
// Elaborate only if we can find a best matching type in the target union

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I removed this union from here because it was misleading - the containing function handles both unions and intersections. However, from what I can tell reportErrors: true is only ever passed in for unions - I can revert this if requested

// Elaborate only if we can find a best matching type in the target union
const bestMatchingType = getBestMatchingType(source, target, isRelatedTo);
// Elaborate only if we can find a best matching type in the target
const bestMatchingType = getBestMatchingType(source, target, /*matchSingleOverlappy*/ true, isRelatedTo);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Returning a single overlappy type is required here to make the non-elementwise union-based elaboration to elaborate about the "last" element in the union, see the "recovered" errors in this commit: e9d136a


function findBestTypeForObjectLiteral(source: Type, unionTarget: UnionOrIntersectionType) {
if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && someType(unionTarget, isArrayLikeType)) {
return find(unionTarget.types, t => !isArrayLikeType(t));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The referenced bug was a somewhat funny one because optional properties always include | undefined in their types and undefinedType is always kept at the beginning of unionType.types. So in such a situation this was always returning that undefinedType - making it impossible to create a good elementwise elaboration.

!(t.flags & TypeFlags.Primitive) &&
!isArrayLikeType(t) &&
!typeHasCallOrConstructSignatures(t) &&
(everyContainedType(t, t => !t.symbol || !(t.symbol.flags & SymbolFlags.Class)) || !containsNonPublicProperties(getAugmentedPropertiesOfType(t))));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

this is quite related to #56183 - although completions and contextual types are orthogonal to elementwise elaborations. I only figured out that I should filter those nominal types here because I was working on that other PR in the past

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Changed errors here might feel a little bit questionable. I feel like it's a good change and that it indirectly matches some other situations.

Let's take a look at this one:

functiontest(_: {children: [string,number]|boolean[]}){}constchildren=[{},""]satisfies[unknown,unknown];test({// Type '[{}, string]' is not assignable to type '[string, number] | boolean[]'.// Type '[{}, string]' is not assignable to type '[string, number]'.// Type at position 0 in source is not compatible with type at position 0 in target.// Type '{}' is not assignable to type 'string'.(2322)
children,});

Regardless of the order of this union we get the same error. The tuple gets priority selection here and that's exactly what happens with my changes here. Since getBestMatchingType gets called before getIndexedAccessTypeOrUndefined I now select the tuple through findMatchingTypeReferenceOrTypeAliasReference.

If you feel strongly about it I can work on special-casing tuples/arrays in this algorithm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Those errors were improved based on overlapping type selection. Even though the discriminant property has the error (so we can't quite know which type it was supposed to be) - the other properties indicate the user's intention.

!!! error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'.
!!! error TS2322: Types of property 'n' are incompatible.
!!! error TS2322: Object literal may only specify known properties, and 'b' does not exist in type 'AN'.
!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'AN'.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This feels like a straight improvement - this was supposed to look like this since #55152 (cc Ryan Cavanaugh (@RyanCavanaugh) - maybe it would be worth rechecking if the approach used by that PR doesn't have any other holes)

@Andarist
Mateusz Burzyński (Andarist)force-pushed the fix/elementwise-errors-best-type-obj-literal branch from 78fd6d9 to e295774CompareFebruary 26, 2024 08:39
@DanielRosenwasser

Copy link
Copy Markdown
Member

TypeScript Bot (@typescript-bot) perf test this

@typescript-bot

TypeScript Bot (typescript-bot) commented Feb 26, 2024

Copy link
Copy Markdown
Contributor

Heya Daniel Rosenwasser (@DanielRosenwasser), I've started to run the regular perf test suite on this PR at e295774. You can monitor the build here.

Update: The results are in!

type: foo1,
~~~~
!!! error TS2322: Type 'string' is not assignable to type '"foo" | "bar"'.
!!! error TS2322: Type 'string' is not assignable to type '"foo"'.

@DanielRosenwasserDaniel Rosenwasser (DanielRosenwasser)Feb 26, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Heh - this is kind of better if you're already familiar with string literals, but I'd argue overall worse in that it doesn't give as much of a hint that type is really the discriminant. I don't think it's a blocker though.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Note that this isn't related to discriminants here. This case just happens to have a discriminant target.

The reason this has changed is that previously getBestMatchIndexedAccessTypeOrUndefined would prefer the simple match done using getIndexedAccessTypeOrUndefined. Since type is a shared property in the union target that would return early and the error with the union type would be raised. Now getBestMatchingType is preferred so this new error here is the product of the best overlappy type matching.

This now matches more closely the non-elementwise error reported in the very same situation, see the playground here

!!! error TS2769: No overload matches this call.
!!! error TS2769: Overload 2 of 2, '(props: PropsType, context: any): Foo', gave the following error.
!!! error TS2769: Type 'unknown' is not assignable to type 'string | boolean'.
!!! error TS2769: Type 'unknown' is not assignable to type 'string'.

Choose a reason for hiding this comment

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

This does seem worse overall, but it feels like JSX children should have better messages.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I touched on this here. Let me know if that makes any sense or if you think I should work more on improving this case.

Comment on lines +43 to +44
!!! error TS2322: Type 'number' is not assignable to type 'undefined'.
!!! related TS6500 objectLiteralNormalization.ts:11:19: The expected type comes from property 'b' which is declared here on type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'

Choose a reason for hiding this comment

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

Unlike the other regressions, it really feels like we've lost too much context here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Doesn't the related info contain the same information that was reported previously in the non-elementwise error? What would be your ideal outcome here? It could be nicer if the error would focus on the selected best type and not on the containing union.

I wouldn't call this bit a regression per se - the same information is still here, it's presented differently though. And, of course, the presentation does matter - I'm not claiming that it doesn't.

@fatcerberusBruce Pascoe (fatcerberus)Mar 4, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FWIW: That error is confusing. It starts out saying number isn't assignable to undefined, which is true, but then goes on to claim that the "expected type" comes from b of { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }. Now, given that union as the target type, if the b in the source is the only problem... why can't it be a number? So the error by itself kinda-sorta contradicts itself and requires an additional elementwise error saying a is also the wrong type to clear things up.

tl;dr: the error message isn’t a complete description of the problem, you also need to know what the source type of a is to understand why there’s an error at all

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It makes sense. When rereading it now I see how this is confusing - perhaps the related information should mention the complete source type or it should somehow mention the selected best type based on which this elementwise elaboration is produced.

I'll look into improving this - thanks for the feedback ❤️

@typescript-bot

Copy link
Copy Markdown
Contributor

Daniel Rosenwasser (@DanielRosenwasser)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Angular - node (v18.15.0, x64)
Memory used295,637k (± 0.01%)295,682k (± 0.01%)+45k (+ 0.02%)295,637k295,708kp=0.025 n=6
Parse Time2.67s (± 0.31%)2.67s (± 0.28%)~2.66s2.68sp=0.209 n=6
Bind Time0.84s (± 1.06%)0.83s (± 0.76%)~0.82s0.84sp=0.070 n=6
Check Time8.25s (± 0.44%)8.26s (± 0.35%)~8.22s8.28sp=0.685 n=6
Emit Time7.09s (± 0.26%)7.10s (± 0.29%)~7.09s7.13sp=0.437 n=6
Total Time18.84s (± 0.31%)18.86s (± 0.15%)~18.81s18.89sp=0.325 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used193,496k (± 1.54%)192,545k (± 1.25%)~191,513k197,474kp=0.575 n=6
Parse Time1.36s (± 1.46%)1.35s (± 0.81%)~1.33s1.36sp=0.397 n=6
Bind Time0.72s (± 0.00%)0.72s (± 0.00%)~0.72s0.72sp=1.000 n=6
Check Time9.37s (± 0.28%)9.36s (± 0.44%)~9.31s9.43sp=0.683 n=6
Emit Time2.62s (± 0.45%)2.60s (± 0.51%)-0.02s (- 0.76%)2.59s2.62sp=0.039 n=6
Total Time14.06s (± 0.19%)14.04s (± 0.32%)~13.96s14.09sp=0.260 n=6
Monaco - node (v18.15.0, x64)
Memory used347,470k (± 0.01%)347,476k (± 0.00%)~347,456k347,491kp=0.521 n=6
Parse Time2.47s (± 0.47%)2.46s (± 1.30%)~2.40s2.49sp=0.933 n=6
Bind Time0.92s (± 0.56%)0.93s (± 1.99%)~0.92s0.97sp=0.247 n=6
Check Time6.96s (± 0.47%)6.95s (± 0.35%)~6.91s6.98sp=0.627 n=6
Emit Time4.05s (± 0.56%)4.05s (± 0.58%)~4.02s4.08sp=1.000 n=6
Total Time14.42s (± 0.16%)14.40s (± 0.34%)~14.33s14.45sp=0.935 n=6
TFS - node (v18.15.0, x64)
Memory used302,871k (± 0.01%)302,863k (± 0.00%)~302,852k302,879kp=0.688 n=6
Parse Time2.01s (± 0.75%)2.01s (± 0.81%)~1.99s2.04sp=0.415 n=6
Bind Time1.00s (± 1.22%)1.00s (± 0.81%)~1.00s1.02sp=1.000 n=6
Check Time6.34s (± 0.34%)6.35s (± 0.37%)~6.33s6.39sp=0.625 n=6
Emit Time3.58s (± 0.41%)3.59s (± 0.81%)~3.56s3.64sp=0.746 n=6
Total Time12.94s (± 0.16%)12.96s (± 0.28%)~12.92s13.02sp=0.195 n=6
material-ui - node (v18.15.0, x64)
Memory used511,311k (± 0.01%)511,281k (± 0.00%)~511,263k511,312kp=0.575 n=6
Parse Time2.66s (± 0.60%)2.66s (± 0.28%)~2.65s2.67sp=0.676 n=6
Bind Time0.99s (± 0.84%)0.99s (± 1.04%)~0.98s1.01sp=0.788 n=6
Check Time17.26s (± 0.54%)17.24s (± 0.22%)~17.19s17.29sp=1.000 n=6
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)~0.00s0.00sp=1.000 n=6
Total Time20.92s (± 0.40%)20.89s (± 0.23%)~20.82s20.95sp=0.809 n=6
mui-docs - node (v18.15.0, x64)
Memory used2,294,916k (± 0.00%)2,294,889k (± 0.00%)~2,294,776k2,294,977kp=0.521 n=6
Parse Time12.00s (± 0.86%)12.06s (± 1.14%)~11.92s12.30sp=0.521 n=6
Bind Time2.64s (± 0.54%)2.64s (± 0.34%)~2.63s2.65sp=1.000 n=6
Check Time101.56s (± 0.75%)101.54s (± 0.70%)~100.57s102.45sp=0.936 n=6
Emit Time0.32s (± 0.00%)0.32s (± 1.28%)~0.31s0.32sp=0.405 n=6
Total Time116.53s (± 0.59%)116.56s (± 0.66%)~115.55s117.57sp=1.000 n=6
self-build-src - node (v18.15.0, x64)
Memory used2,406,124k (± 0.02%)2,406,232k (± 0.03%)~2,405,206k2,407,111kp=0.689 n=6
Parse Time5.06s (± 0.95%)5.06s (± 0.95%)~5.00s5.11sp=0.810 n=6
Bind Time1.89s (± 0.99%)1.88s (± 0.78%)~1.86s1.90sp=0.808 n=6
Check Time33.63s (± 0.14%)33.75s (± 0.49%)~33.47s33.95sp=0.066 n=6
Emit Time2.69s (± 1.19%)2.69s (± 1.50%)~2.64s2.75sp=0.810 n=6
Total Time43.29s (± 0.21%)43.40s (± 0.41%)~43.09s43.62sp=0.128 n=6
self-compiler - node (v18.15.0, x64)
Memory used419,243k (± 0.00%)419,297k (± 0.01%)+55k (+ 0.01%)419,251k419,413kp=0.020 n=6
Parse Time2.80s (± 2.38%)2.78s (± 1.89%)~2.69s2.82sp=0.376 n=6
Bind Time1.10s (± 5.36%)1.13s (± 6.30%)~1.08s1.22sp=0.167 n=6
Check Time15.28s (± 0.25%)15.28s (± 0.56%)~15.16s15.41sp=1.000 n=6
Emit Time1.15s (± 0.90%)1.14s (± 0.92%)~1.13s1.16sp=0.801 n=6
Total Time20.32s (± 0.24%)20.33s (± 0.46%)~20.19s20.42sp=0.810 n=6
vscode - node (v18.15.0, x64)
Memory used2,849,337k (± 0.00%)2,849,326k (± 0.00%)~2,849,213k2,849,438kp=0.936 n=6
Parse Time10.76s (± 0.08%)10.75s (± 0.25%)~10.72s10.78sp=0.738 n=6
Bind Time3.43s (± 0.15%)3.44s (± 0.31%)~3.42s3.45sp=0.794 n=6
Check Time60.59s (± 0.23%)60.77s (± 0.11%)+0.18s (+ 0.30%)60.67s60.84sp=0.029 n=6
Emit Time16.28s (± 0.43%)16.28s (± 0.82%)~16.12s16.47sp=1.000 n=6
Total Time91.06s (± 0.11%)91.23s (± 0.18%)~91.02s91.44sp=0.128 n=6
webpack - node (v18.15.0, x64)
Memory used396,877k (± 0.01%)396,889k (± 0.01%)~396,846k396,981kp=1.000 n=6
Parse Time3.16s (± 0.54%)3.17s (± 0.45%)~3.15s3.19sp=0.287 n=6
Bind Time1.40s (± 0.37%)1.40s (± 0.75%)~1.38s1.41sp=0.794 n=6
Check Time14.12s (± 0.19%)14.08s (± 0.40%)~13.99s14.13sp=0.291 n=6
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)~0.00s0.00sp=1.000 n=6
Total Time18.67s (± 0.20%)18.64s (± 0.35%)~18.53s18.69sp=0.744 n=6
xstate - node (v18.15.0, x64)
Memory used513,446k (± 0.01%)513,429k (± 0.01%)~513,377k513,520kp=0.471 n=6
Parse Time3.27s (± 0.27%)3.28s (± 0.30%)~3.27s3.29sp=0.082 n=6
Bind Time1.54s (± 0.41%)1.54s (± 0.35%)~1.54s1.55sp=0.201 n=6
Check Time2.87s (± 0.58%)2.89s (± 0.78%)~2.87s2.93sp=0.105 n=6
Emit Time0.08s (± 0.00%)0.08s (± 7.90%)~0.07s0.09sp=1.000 n=6
Total Time7.76s (± 0.34%)7.80s (± 0.39%)~7.76s7.85sp=0.065 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Angular - node (v18.15.0, x64)
  • Compiler-Unions - node (v18.15.0, x64)
  • Monaco - node (v18.15.0, x64)
  • TFS - node (v18.15.0, x64)
  • material-ui - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

tsserver

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-UnionsTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,351ms (± 0.38%)2,342ms (± 0.77%)~2,324ms2,373msp=0.261 n=6
Req 2 - geterr5,507ms (± 1.10%)5,579ms (± 1.12%)~5,496ms5,653msp=0.066 n=6
Req 3 - references327ms (± 1.76%)325ms (± 1.00%)~322ms331msp=0.568 n=6
Req 4 - navto277ms (± 0.84%)274ms (± 1.32%)~272ms279msp=0.212 n=6
Req 5 - completionInfo count1,357 (± 0.00%)1,357 (± 0.00%)~1,3571,357p=1.000 n=6
Req 5 - completionInfo82ms (± 6.45%)90ms (± 6.65%)🔻+8ms (+ 9.15%)80ms94msp=0.021 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,472ms (± 0.74%)2,479ms (± 0.76%)~2,454ms2,509msp=0.378 n=6
Req 2 - geterr4,177ms (± 1.73%)4,226ms (± 1.86%)~4,115ms4,283msp=0.298 n=6
Req 3 - references336ms (± 1.48%)334ms (± 0.92%)~331ms340msp=0.686 n=6
Req 4 - navto284ms (± 0.43%)286ms (± 1.29%)~282ms291msp=1.000 n=6
Req 5 - completionInfo count1,519 (± 0.00%)1,519 (± 0.00%)~1,5191,519p=1.000 n=6
Req 5 - completionInfo86ms (± 7.40%)81ms (± 6.30%)~77ms89msp=0.166 n=6
xstateTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,603ms (± 0.55%)2,610ms (± 0.54%)~2,593ms2,626msp=0.572 n=6
Req 2 - geterr1,736ms (± 2.44%)1,758ms (± 1.27%)~1,724ms1,791msp=0.575 n=6
Req 3 - references114ms (± 9.19%)120ms (± 8.94%)~106ms127msp=1.000 n=6
Req 4 - navto370ms (± 0.17%)371ms (± 0.28%)~369ms372msp=0.388 n=6
Req 5 - completionInfo count2,079 (± 0.00%)2,079 (± 0.00%)~2,0792,079p=1.000 n=6
Req 5 - completionInfo311ms (± 1.52%)314ms (± 1.09%)~309ms317msp=0.169 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • CompilerTSServer - node (v18.15.0, x64)
  • Compiler-UnionsTSServer - node (v18.15.0, x64)
  • xstateTSServer - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

startup

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
tsc-startup - node (v18.15.0, x64)
Execution time153.89ms (± 0.19%)153.80ms (± 0.18%)-0.09ms (- 0.06%)152.88ms157.83msp=0.004 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time229.96ms (± 0.15%)229.86ms (± 0.17%)-0.11ms (- 0.05%)228.32ms235.35msp=0.000 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time231.83ms (± 0.19%)232.02ms (± 0.19%)+0.19ms (+ 0.08%)230.47ms236.77msp=0.000 n=600
typescript-startup - node (v18.15.0, x64)
Execution time231.10ms (± 0.18%)231.13ms (± 0.18%)~229.70ms237.75msp=0.597 n=600
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • tsc-startup - node (v18.15.0, x64)
  • tsserver-startup - node (v18.15.0, x64)
  • tsserverlibrary-startup - node (v18.15.0, x64)
  • typescript-startup - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

Developer Information:

Download Benchmarks

…s-best-type-obj-literal
# Conflicts:
#	src/compiler/utilities.ts
CopilotAI review requested due to automatic review settings August 7, 2025 10:35

CopilotAI 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

This PR improves error location reporting for elementwise error elaborations when type checking object literals against union types. It focuses on finding better property candidates for printed errors, making the highlighted error locations more precise and less distracting by reducing error spans when appropriate.

Key changes:

  • Enhanced best type matching algorithm for union types to better handle object literal assignments
  • Moved and improved the containsNonPublicProperties utility function to handle private fields
  • Updated error elaboration logic to provide more targeted error locations

Reviewed Changes

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

Show a summary per file
FileDescription
src/compiler/checker.tsCore logic changes for improved best type matching and error elaboration
src/compiler/utilities.tsAdded enhanced containsNonPublicProperties utility function
src/services/completions.tsRemoved duplicate containsNonPublicProperties function and imported from utilities
tests/cases/compiler/elementWiseErrorInUnionTarget*.tsNew test cases covering various union type scenarios
tests/baselines/reference/*.errors.txtUpdated baseline files showing improved error locations
Comments suppressed due to low confidence (2)

return some(props, p =>
!!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier) ||
!!p.valueDeclaration && isNamedDeclaration(p.valueDeclaration) && isPrivateIdentifier(p.valueDeclaration.name));
}

CopilotAIAug 7, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] The complex boolean expression checking for private identifiers could be extracted into a separate helper function for better readability and reusability.

Suggested change
}
exportfunctioncontainsNonPublicProperties(props: Symbol[]): boolean{
returnsome(props,p=>
!!(getDeclarationModifierFlagsFromSymbol(p)&ModifierFlags.NonPublicAccessibilityModifier)||
hasPrivateIdentifierName(p)
);
}
functionhasPrivateIdentifierName(p: Symbol): boolean{
return!!p.valueDeclaration&&isNamedDeclaration(p.valueDeclaration)&&isPrivateIdentifier(p.valueDeclaration.name);
}

Copilot uses AI. Check for mistakes.
@typescript-bot

Copy link
Copy Markdown
Contributor

With 6.0 out as the final release vehicle for this codebase, we're closing all PRs that don't fit the merge criteria for post-6.0 patches. If you think this was a mistake and this PR fits the post-6.0 patch criteria, please post to the 6.0 iteration issue with details (specifically, which PR and which patch criteria it satisfies).

Next steps for PRs:

  • For crash bugfixes or language service improvements, PRs are currently accepted at the typescript-go repo
  • Changes to type system behavior should wait until after 7.0, at which point mainline TypeScript development will resume in this repository with the Go codebase
  • Library file updates (lib.d.ts etc) continue to live in this repo or the DOM Generator repo as appropriate

@github-project-automationgithub-project-automationBot moved this from Waiting on reviewers to Done in PR BacklogMar 24, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Backlog BugPRs that fix a backlog bug

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Wrong elementwise error location on optional object property that allows arrays too

8 participants

@Andarist@DanielRosenwasser@typescript-bot@fatcerberus@sandersn@weswigham@RyanCavanaugh