Skip to content

Add optionality to mapped type indexed access substitutions - #57549

Merged
Anders Hejlsberg (ahejlsberg) merged 5 commits into
mainfrom
fix57487
Mar 4, 2024
Merged

Add optionality to mapped type indexed access substitutions#57549
Anders Hejlsberg (ahejlsberg) merged 5 commits into
mainfrom
fix57487

Conversation

@ahejlsberg

Copy link
Copy Markdown
Member

Fixes#57487.

@ahejlsberg

Copy link
Copy Markdown
MemberAuthor

@typescript-bot

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

Copy link
Copy Markdown
Contributor

Heya Anders Hejlsberg (@ahejlsberg), I've started to run the faster perf test suite on this PR at ab3184b. You can monitor the build here.

Update: The results are in!

@typescript-bot

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

Copy link
Copy Markdown
Contributor

Heya Anders Hejlsberg (@ahejlsberg), I've started to run the diff-based top-repos suite on this PR at ab3184b. You can monitor the build here.

Update: The results are in!

@typescript-bot

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

Copy link
Copy Markdown
Contributor

Heya Anders Hejlsberg (@ahejlsberg), I've started to run the parallelized Definitely Typed test suite on this PR at ab3184b. You can monitor the build here.

Update: The results are in!

@typescript-bot

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

Copy link
Copy Markdown
Contributor

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

Update: The results are in!

@typescript-bot

Copy link
Copy Markdown
Contributor

Anders Hejlsberg (@ahejlsberg) Here are the results of running the user test suite comparing main and refs/pull/57549/merge:

There were infrastructure failures potentially unrelated to your change:

  • 1 instance of "Package install failed"

Otherwise...

Something interesting changed - please have a look.

Details

puppeteer

packages/browsers/test/src/tsconfig.json

@typescript-bot

Copy link
Copy Markdown
Contributor

Anders Hejlsberg (@ahejlsberg)
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,642k (± 0.00%)295,638k (± 0.01%)~295,619k295,665kp=0.873 n=6
Parse Time2.66s (± 0.31%)2.66s (± 0.39%)~2.65s2.68sp=0.932 n=6
Bind Time0.83s (± 0.90%)0.83s (± 0.90%)~0.82s0.84sp=1.000 n=6
Check Time8.27s (± 0.25%)8.22s (± 0.31%)-0.04s (- 0.54%)8.19s8.26sp=0.018 n=6
Emit Time7.10s (± 0.37%)7.11s (± 0.20%)~7.09s7.13sp=0.567 n=6
Total Time18.87s (± 0.08%)18.83s (± 0.20%)~18.80s18.90sp=0.052 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used192,582k (± 1.23%)194,569k (± 1.68%)~191,561k197,655kp=0.689 n=6
Parse Time1.36s (± 1.08%)1.37s (± 1.13%)~1.35s1.39sp=0.220 n=6
Bind Time0.72s (± 0.00%)0.72s (± 0.57%)~0.72s0.73sp=0.405 n=6
Check Time9.33s (± 0.31%)9.36s (± 0.46%)~9.29s9.41sp=0.261 n=6
Emit Time2.61s (± 0.40%)2.63s (± 1.05%)~2.60s2.67sp=0.183 n=6
Total Time14.02s (± 0.21%)14.08s (± 0.47%)~13.98s14.16sp=0.108 n=6
Monaco - node (v18.15.0, x64)
Memory used347,467k (± 0.00%)347,480k (± 0.00%)~347,461k347,492kp=0.228 n=6
Parse Time2.48s (± 0.78%)2.48s (± 0.71%)~2.46s2.50sp=0.869 n=6
Bind Time0.93s (± 0.44%)0.93s (± 0.56%)~0.92s0.93sp=0.595 n=6
Check Time6.94s (± 0.27%)6.96s (± 0.75%)~6.91s7.03sp=0.872 n=6
Emit Time4.05s (± 0.48%)4.07s (± 0.30%)~4.05s4.08sp=0.254 n=6
Total Time14.41s (± 0.29%)14.43s (± 0.34%)~14.38s14.50sp=0.295 n=6
TFS - node (v18.15.0, x64)
Memory used302,876k (± 0.01%)302,864k (± 0.01%)~302,850k302,892kp=0.298 n=6
Parse Time2.02s (± 0.70%)2.01s (± 0.58%)~2.00s2.03sp=0.161 n=6
Bind Time1.00s (± 1.03%)1.00s (± 0.83%)~1.00s1.02sp=0.788 n=6
Check Time6.36s (± 0.29%)6.35s (± 0.18%)~6.33s6.36sp=0.367 n=6
Emit Time3.59s (± 0.21%)3.60s (± 0.27%)~3.59s3.61sp=0.102 n=6
Total Time12.97s (± 0.23%)12.96s (± 0.18%)~12.92s12.99sp=1.000 n=6
material-ui - node (v18.15.0, x64)
Memory used511,279k (± 0.01%)511,286k (± 0.00%)~511,259k511,314kp=0.471 n=6
Parse Time2.65s (± 0.67%)2.67s (± 0.64%)~2.64s2.69sp=0.104 n=6
Bind Time1.00s (± 1.05%)0.99s (± 0.82%)~0.99s1.01sp=0.720 n=6
Check Time17.28s (± 0.38%)17.28s (± 0.59%)~17.14s17.41sp=1.000 n=6
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)~0.00s0.00sp=1.000 n=6
Total Time20.92s (± 0.37%)20.94s (± 0.51%)~20.80s21.08sp=1.000 n=6
mui-docs - node (v18.15.0, x64)
Memory used2,294,952k (± 0.00%)2,294,958k (± 0.00%)~2,294,894k2,294,998kp=0.810 n=6
Parse Time11.93s (± 0.66%)11.99s (± 0.44%)~11.93s12.06sp=0.199 n=6
Bind Time2.65s (± 0.37%)2.65s (± 0.60%)~2.62s2.66sp=0.388 n=6
Check Time101.92s (± 0.76%)101.57s (± 0.78%)~100.76s102.77sp=0.470 n=6
Emit Time0.32s (± 0.00%)0.32s (± 0.00%)~0.32s0.32sp=1.000 n=6
Total Time116.82s (± 0.63%)116.53s (± 0.69%)~115.67s117.70sp=0.688 n=6
self-build-src - node (v18.15.0, x64)
Memory used2,406,997k (± 0.02%)2,406,178k (± 0.02%)-820k (- 0.03%)2,405,356k2,406,554kp=0.020 n=6
Parse Time5.09s (± 0.79%)5.07s (± 1.21%)~5.01s5.17sp=0.471 n=6
Bind Time1.87s (± 0.63%)1.88s (± 0.34%)~1.87s1.89sp=0.070 n=6
Check Time33.67s (± 0.23%)33.63s (± 0.35%)~33.49s33.77sp=0.470 n=6
Emit Time2.64s (± 1.88%)2.70s (± 2.14%)~2.60s2.76sp=0.109 n=6
Total Time43.28s (± 0.21%)43.30s (± 0.29%)~43.10s43.44sp=0.810 n=6
self-compiler - node (v18.15.0, x64)
Memory used419,200k (± 0.01%)419,176k (± 0.01%)~419,124k419,236kp=0.230 n=6
Parse Time2.82s (± 0.45%)2.83s (± 0.88%)~2.81s2.88sp=0.459 n=6
Bind Time1.08s (± 0.51%)1.07s (± 0.38%)~1.07s1.08sp=0.282 n=6
Check Time15.25s (± 0.21%)15.21s (± 0.45%)~15.13s15.32sp=0.199 n=6
Emit Time1.14s (± 1.80%)1.14s (± 1.08%)~1.12s1.15sp=0.454 n=6
Total Time20.29s (± 0.27%)20.24s (± 0.25%)~20.20s20.33sp=0.295 n=6
vscode - node (v18.15.0, x64)
Memory used2,849,301k (± 0.00%)2,849,285k (± 0.00%)~2,849,178k2,849,346kp=0.226 n=6
Parse Time10.74s (± 0.21%)10.77s (± 0.54%)~10.68s10.82sp=0.332 n=6
Bind Time3.43s (± 0.24%)3.44s (± 0.71%)~3.41s3.48sp=0.243 n=6
Check Time60.73s (± 0.32%)60.58s (± 0.14%)~60.48s60.69sp=0.126 n=6
Emit Time16.85s (± 7.93%)16.25s (± 0.19%)~16.21s16.28sp=0.090 n=6
Total Time91.75s (± 1.58%)91.03s (± 0.11%)~90.92s91.16sp=0.065 n=6
webpack - node (v18.15.0, x64)
Memory used396,927k (± 0.03%)396,930k (± 0.01%)~396,875k396,981kp=0.575 n=6
Parse Time3.17s (± 1.24%)3.16s (± 0.95%)~3.13s3.21sp=0.685 n=6
Bind Time1.38s (± 1.18%)1.39s (± 0.59%)~1.38s1.40sp=0.186 n=6
Check Time14.06s (± 0.44%)14.10s (± 0.44%)~14.02s14.20sp=0.199 n=6
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)~0.00s0.00sp=1.000 n=6
Total Time18.61s (± 0.42%)18.66s (± 0.44%)~18.58s18.81sp=0.518 n=6
xstate - node (v18.15.0, x64)
Memory used513,437k (± 0.01%)513,434k (± 0.01%)~513,386k513,514kp=0.689 n=6
Parse Time3.28s (± 0.36%)3.27s (± 0.12%)~3.27s3.28sp=0.087 n=6
Bind Time1.55s (± 0.53%)1.54s (± 0.76%)~1.53s1.56sp=0.401 n=6
Check Time2.87s (± 0.87%)2.86s (± 0.58%)~2.84s2.88sp=0.324 n=6
Emit Time0.08s (± 0.00%)0.08s (± 0.00%)~0.08s0.08sp=1.000 n=6
Total Time7.78s (± 0.35%)7.76s (± 0.20%)~7.75s7.79sp=0.184 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

Developer Information:

Download Benchmarks

@typescript-bot

Copy link
Copy Markdown
Contributor

Hey Anders Hejlsberg (@ahejlsberg), the results of running the DT tests are ready.
Everything looks the same!
You can check the log here.

0;
}

function getCombinedMappedTypeOptionality(type: MappedType): number {

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.

If I'm not mistaken this currently falls short here:

typeObj={a: 1,b: 2};typeIdentity<T>={[KinkeyofT]: T[K]};constmapped: {[KinkeyofIdentity<Partial<Obj>>]: Obj[K]}={}constresolveMapped=<Kextendskeyoftypeofmapped>(key: K)=>mapped[key].toString();// should error but it doesnt

Some extra handling of homomorphic mapped types might have to be added here.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yeah, looks like we need to recurse in getCombinedMappedTypeOptionality.

@typescript-bot

Copy link
Copy Markdown
Contributor

Anders Hejlsberg (@ahejlsberg) Here are the results of running the top-repos suite comparing main and refs/pull/57549/merge:

Everything looks good!

const templateMapper = combineTypeMappers(objectType.mapper, mapper);
return instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper);
const instantiatedTemplateType = instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper);
return addOptionality(instantiatedTemplateType, /*isProperty*/ true, getCombinedMappedTypeOptionality(objectType) > 0);

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.

Taking known properties into consideration would fix this inconsistency that this PR creates:

typeObj={a: string;b: number;};typeObj2={b: number;c: boolean;};declareconstmapped: {[Kinkeyof(Partial<Obj>&Required<Obj2>)]: number;};// displays the same way as `resolved` below!mapped;// ^? const mapped: { a?: number | undefined; b: number; c: number; }constaccessMapped=<KextendskeyofObj2>(key: K)=>mapped[key].toString();declareconstresolved: {a?: number|undefined;b: number;c: number};constaccessResolved=<KextendskeyofObj2>(key: K)=>resolved[key].toString();

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Right, when mapping over intersections constructed from multiple mapped types the PR makes the most conservative assumption about optionality. I think that's an acceptable compromise and I'm concerned with the potential cost of examining every member possibly selected by the key.

return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0;
}

function getModifiersTypeOptionality(type: Type): number {

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.

I don't understand what this is computing. What does a result of 2 mean?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

The result is always either -1, 0, or 1. -1 means optionality is stripped (i.e. -?), 0 means optionality is unchanged, 1 means optionality is added (i.e. +?). When a homomorphic mapped type doesn't modify optionality, we (recursively) consult the optionality of the type you're mapping over to see if it strips or adds optionality.

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.

Should this be an enum? Then it'd be easier to tell what the numbers mean.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

It could be an enum, but number feels more appropriate since we use the greater and less than operators to relate the combined values.

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.

Would a comment about what each number represents work?

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.

Behavior looks good

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Author: TeamFor Uncommitted BugPR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: Indexed Access of Partial Mapped Type with Union from Generic Function is missing undefined

5 participants

@ahejlsberg@typescript-bot@RyanCavanaugh@Andarist@gabritto