Skip to content

perf(form-core): reduce instantiations when type checking #1262

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 39 commits into from
Apr 2, 2025

Conversation

chorobin
Copy link
Contributor

@chorobin chorobin commented Mar 9, 2025

I have used the large example in the repo (this isn't very large so difference is not so large) to check reduction in instantiations and type checking time. I am using extendedDiagnostics but also traced the example

Before:

> tsc "--extendedDiagnostics"

Files:                         215
Lines of Library:            43159
Lines of Definitions:        80538
Lines of TypeScript:           209
Lines of JavaScript:             0
Lines of JSON:                   0
Lines of Other:                  0
Identifiers:                105350
Symbols:                    118110
Types:                       18129
Instantiations:             205206
Memory used:               157045K
Assignability cache size:     9324
Identity cache size:           223
Subtype cache size:              5
Strict subtype cache size:       0
I/O Read time:               0.05s
Parse time:                  0.43s
ResolveModule time:          0.09s
ResolveTypeReference time:   0.00s
ResolveLibrary time:         0.02s
Program time:                0.66s
Bind time:                   0.21s
Check time:                  0.71s
printTime time:              0.00s
Emit time:                   0.00s
Total time:                  1.58s

After

> tsc "--extendedDiagnostics"

Files:                         215
Lines of Library:            43159
Lines of Definitions:        80528
Lines of TypeScript:           209
Lines of JavaScript:             0
Lines of JSON:                   0
Lines of Other:                  0
Identifiers:                105504
Symbols:                     85611
Types:                        6188
Instantiations:              27643
Memory used:               133987K
Assignability cache size:     1640
Identity cache size:           166
Subtype cache size:              5
Strict subtype cache size:      12
I/O Read time:               0.05s
Parse time:                  0.44s
ResolveModule time:          0.10s
ResolveTypeReference time:   0.00s
ResolveLibrary time:         0.02s
Program time:                0.68s
Bind time:                   0.21s
Check time:                  0.37s
printTime time:              0.00s
Emit time:                   0.00s
Total time:                  1.26s

There are three main things contributing to lower instantiations:

  1. Variance annotations have been added, this means when comparing two types with different type parameters, the variance worker takes less time as we are hinting to the compiler how our type parameters are going to be used
  2. TName is not constrained and uses a ValidateName utility instead. I prefer not to use contraints at inference sites against complex types that could be unions. This is because TName could default to the union and this can slow things down in a few situations.
  3. I re-worked DeepKeys and DeepValue. Instead of creating a union and then parsing TName again, a map is constructed so TValue can be grabbed by TName. TName -> TValue

Copy link

nx-cloud bot commented Mar 9, 2025

View your CI Pipeline Execution ↗ for commit ea07bce.

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 2m 21s View ↗
nx run-many --target=build --exclude=examples/** ✅ Succeeded 18s View ↗

☁️ Nx Cloud last updated this comment at 2025-04-02 16:29:47 UTC

Copy link

pkg-pr-new bot commented Mar 9, 2025

More templates

@tanstack/angular-form

npm i https://pkg.pr.new/@tanstack/angular-form@1262

@tanstack/form-core

npm i https://pkg.pr.new/@tanstack/form-core@1262

@tanstack/react-form

npm i https://pkg.pr.new/@tanstack/react-form@1262

@tanstack/lit-form

npm i https://pkg.pr.new/@tanstack/lit-form@1262

@tanstack/solid-form

npm i https://pkg.pr.new/@tanstack/solid-form@1262

@tanstack/vue-form

npm i https://pkg.pr.new/@tanstack/vue-form@1262

commit: ea07bce

Copy link

codecov bot commented Mar 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.86%. Comparing base (ce177f0) to head (ea07bce).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1262      +/-   ##
==========================================
- Coverage   88.88%   88.86%   -0.02%     
==========================================
  Files          28       28              
  Lines        1277     1275       -2     
  Branches      335      332       -3     
==========================================
- Hits         1135     1133       -2     
  Misses        126      126              
  Partials       16       16              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

chorobin and others added 22 commits March 10, 2025 22:04
@chorobin chorobin marked this pull request as ready for review March 10, 2025 23:28
Copy link
Member

@Balastrong Balastrong left a comment

Choose a reason for hiding this comment

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

Thanks for the improvements and sorry for taking so long for the review!

I just added a couple comments, overall looks great! (and slightly beyond my TS knowledge, but I trust you :D)

@@ -24,8 +24,13 @@ assertType<
type ArraySupport = DeepKeys<{ users: User[] }>
assertType<
| 'users'
| `users[number]`
Copy link
Member

Choose a reason for hiding this comment

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

Question: the types with [number] are added to ArrayAccessor on purpose for the autocomplete, right?

I see it goes from this (on main)
image

to this
image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, what do you think about this? Would you prefer it is not here?

Copy link
Member

Choose a reason for hiding this comment

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

Let's talk about it.

At the current state you don't get any suggestion. With this change we're showing/accepting a value that is technically wrong (people[number].age does not exist and will throw an error at runtime) but points to the right direction, showing an example of what you can do.
The runtime error might be annoying as it's not much self explanatory, I tried and I got Uncaught TypeError: field.state.value.map is not a function only after editing an item of an array.

I don't know, since it's just a type change we might even let this in and remove it later if people get more confused than helped but in my case at first I thought it was an error, then I realized it was probably a nice hint.

@crutchcorn and @harry-whorlow what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, yeah. Thinking about it. I don't think this is a good idea to have for now. I think ideally it should show as a suggestion but then type error if you actually use it. But this then requires the user to edit the type after they have selected it which I'm not sure if I like

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this something that we've seen requested? So far to me it seems like potentially adding complexity in a situation where the benefit isn't that apparent... But either way I don't have a strong opinion. 😊

@Balastrong Balastrong force-pushed the perf-annotations-deep-key-values branch from 8efda0a to 3a3de2e Compare April 2, 2025 16:08
@Balastrong Balastrong merged commit 4e15826 into TanStack:main Apr 2, 2025
6 checks passed
@Balastrong
Copy link
Member

I'm merging it to avoid conflicts on long lived branches, thanks again!

juanvilladev pushed a commit to juanvilladev/form that referenced this pull request Apr 3, 2025
)

* perf: add variance annotations

* perf(form-core): improve ts performance for large example

* ci: apply automated fixes and generate docs

* perf(form-core): rework to use UnionToIntersection, add other variance annotations and remove Omit

* ci: apply automated fixes and generate docs

* fix: revert some variance annotations for later

* ci: apply automated fixes and generate docs

* chore: fix knip

* chore: remove omit

* ci: apply automated fixes and generate docs

* perf(solid-form): apply interface performance improvments to solid

* ci: apply automated fixes and generate docs

* perf(vue-form): add interface changes to vue

* ci: apply automated fixes and generate docs

* chore: cleanup

* ci: apply automated fixes and generate docs

* chore: cleanup

* ci: apply automated fixes and generate docs

* refactor: use mapped type instead of union to intersection

* ci: apply automated fixes and generate docs

* chore: fix build

* ci: apply automated fixes and generate docs

* chore: change back to 'name'

* ci: apply automated fixes and generate docs

* fix: remove [number]

* ci: apply automated fixes and generate docs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants