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

Lookup return type of factory function for JSX expression return types #29818

Closed
wants to merge 7 commits into from

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Feb 8, 2019

Fixes #21699
Fixes #14729 mostly

This is a small change, but with potentially high performance implications.

Done-ish:

  • Profile on real-world JSX

Maybe worth doing?:

  • Add some stress-tests using the real react createElement constructor (complete with overloads).
  • Potentially add a flag to the extra disable analysis

links.jsxFactoryCall.end = node.end;
links.jsxFactoryCall.parent = node.parent;
}
const result = getReturnTypeOfSignature(getResolvedSignature(links.jsxFactoryCall));
Copy link

@Jessidhia Jessidhia Feb 14, 2019

Choose a reason for hiding this comment

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

Could this potentially let us get rid of JSX.Element (or, heck, the entire JSX namespace)? 🤔

If we can do that and redefine createElement / React.ReactElement we might be able to get strong type checking for element children, and more 🎉

sounds like an excellent opportunity for a breaking change, almost all of the overloads in createElement were obsoleted by conditional types too and only can't be fixed because it'd be breaking

Copy link
Member Author

Choose a reason for hiding this comment

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

That would be what one would hope for, yeah. Technically we don't want to be rid of it quite yet because there's no way to define the factory function that correctly resolves overloads on components (or generics), but by and large if we had those this wouldn't need the namespace at all.

@ferdaber
Copy link

So would this essentially make the following equivalent as far as type compatibility goes?

// @jsx factoryFunction

const foo = <MyComponent someProps={myProps} ref={myRef}>{myChildren}</ MyComponent>
const foo2 = factoryFunction(MyComponent, { someProps, ref }, myChildren)

@weswigham
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 27, 2019

Heya @weswigham, I've started to run the Definitely Typed test suite on this PR at f74105a. You can monitor the build here. It should now contribute to this PR's status checks.

@weswigham
Copy link
Member Author

I think this change is actually pretty good - petit-dom only needed a few changes to typecheck all its tests using the factory function to help typecheck (and I've now added a version with those changes to the tests).

@typescript-bot run dt again - I didn't see any react-related changes last run, but just in case~

I would love for some more folks to run this PR on their own jsx codebases and report the perf impact if possible - running tsc with --extendedDiagnostics should dump them. I only have a handful, but it doesn't seem too bad with the current react definitions; but if anyone has any projects that already seem on the slow side, building with this PR and checking out how much slower it makes it would be useful data to us. We though that this might undo the speed wins we got from #25302, which is why we're wary of it.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 28, 2019

Heya @weswigham, I've started to run the Definitely Typed test suite on this PR at cec5c8d. You can monitor the build here. It should now contribute to this PR's status checks.

@ferdaber
Copy link

@weswigham I can volunteer if you can guide how to get this specific version of TS.

@weswigham
Copy link
Member Author

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 28, 2019

Heya @weswigham, I've started to run the tarball bundle task on this PR at cec5c8d. You can monitor the build here. It should now contribute to this PR's status checks.

@weswigham
Copy link
Member Author

weswigham commented Feb 28, 2019

@ferdaber npm i https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/23963/artifacts?artifactName=tgz&fileId=A722FF3B44D002C7083998C3254EAC7DA6926F8D6339BE58BCE3C667A918B2FC02&fileName=typescript-3.4.0-insiders.20190228.tgz&api-version=5.0-preview.3
should do it.

@ferdaber
Copy link

Any specific workflows you'd like me to test?

@weswigham
Copy link
Member Author

weswigham commented Feb 28, 2019

Just checking your codebase - running with the old version of TS with --extendedDiagnostics and on this drop with the same flag, and giving me the diagnostic output for both (it's a block of stats that prints after errors). You could also get a feel for IDE responsiveness, but that's difficult to notice changes in unless something is very wrong, so I wouldn't bother.

@vkrol
Copy link

vkrol commented Mar 1, 2019

@weswigham we have ~400 *.tsx files.
[email protected]:

Files:            2288
Lines:          261817
Nodes:          862706
Identifiers:    285901
Symbols:        414841
Types:          193104
Memory used:   550724K
I/O Read time:   0.38s
Parse time:      1.40s
Program time:    3.60s
Bind time:       0.87s
Check time:      9.27s
Total time:     13.74s

[email protected]:

Files:            2288
Lines:          262269
Nodes:          863338
Identifiers:    285955
Symbols:        440881
Types:          197010
Memory used:   553767K
I/O Read time:   0.34s
Parse time:      1.38s
Program time:    3.64s
Bind time:       1.47s
Check time:      9.96s
Total time:     15.07s

@Swatinem
Copy link
Contributor

Swatinem commented Mar 1, 2019

before

λ tsc -v
Version 3.3.3333
λ tsc --extendedDiagnostics
Files:            2831
Lines:          548259
Nodes:             NaN
Identifiers:       NaN
Symbols:        969589
Types:          207800
Memory used:   895652K
I/O Read time:   0.17s
Parse time:      3.17s
Program time:    4.84s
Bind time:       1.82s
Check time:     14.03s
Total time:     20.69s

after

λ tsc -v
Version 3.4.0-insiders.20190228
λ tsc --extendedDiagnostics

[…]
Found 6 errors.

Files:            2833
Lines:          548772
Nodes:             NaN
Identifiers:       NaN
Symbols:       1040992
Types:          219329
Memory used:   906676K
I/O Read time:   0.22s
Parse time:      2.68s
Program time:    4.39s
Bind time:       2.79s
Check time:     10.69s
Total time:     17.86s

So we have 6 new errors, which are either tsc regressions or errors on our part we would have to fix. Other than that the check time seems to be faster by a bit.
We do have a fairly large codebase using pathmapping rather than project references.

@weswigham
Copy link
Member Author

Are the new errors unique to this branch, or do they appear on tyoescript@next as well? If unique to this branch, do they occur and JSX tags and what are they like? AFAIK, the react factory function is pretty well-typed, but it could be slightly off, since it's not like it's exercised as much as jsx tags have been. As for the check time going down... Maybe due to the errors, tbh.

@Swatinem
Copy link
Contributor

Swatinem commented Mar 1, 2019

tried typescript@next:

λ tsc -v
Version 3.4.0-dev.20190301
λ tsc --extendedDiagnostics
[…]
Found 6 errors.

Files:            2833
Lines:          548772
Nodes:             NaN
Identifiers:       NaN
Symbols:       1041189
Types:          219356
Memory used:   932615K
I/O Read time:   0.14s
Parse time:      3.17s
Program time:    4.83s
Bind time:       3.08s
Check time:     13.79s
Total time:     21.71s

Same 6 errors as with this insiders build.

4 of them look related to https://github.com/eversport/intl-codegen and https://github.com/eversport/pyro-form, two of our own libraries we also open-sourced, so we would have to look into those errors. But they are JSX related.

The 2 remaining errors look like window.getSelection() returns a nullable now, which we have to fix ourselves.

@Swatinem
Copy link
Contributor

Swatinem commented Mar 1, 2019

Just for reference, but since its the same error as in typescript@next, I don’t think this is very relevant to this PR:

[…].tsx:67:84 - error TS2345: Argument of type 'Localized<{}> | Message<{}> | undefined' is not assignable to parameter of type 'Localized<Values> | Message<Values> | undefined'.
  Type 'Localized<{}>' is not assignable to type 'Localized<Values> | Message<Values> | undefined'.
    Type 'Localized<{}>' is not assignable to type 'Localized<Values>'.

67     <PyroForm initialValues={initialValues} errors={getParsedApolloErrorFormFields(error)} onSubmit={onRegistration}>
                                                                                      ~~~~~

@weswigham
Copy link
Member Author

Hmmm, I'd greatly appreciate if you could look into if those new errors make sense and provide a repro (and open an issue) if they don't. But yeah, not related to this PR if they happen on @next, too, which is good for this change~

@Jessidhia what changes were you thinking of applying to the react declarations?

@joeljeske
Copy link

I think this will be an amazing addition to TS, and will provide the ability for new ways to use TSX! What is left to get this finalized?

@weswigham
Copy link
Member Author

What is left to get this finalized?

More testing so we have more confidence, thanks. 🚂

We won't ship this in 3.4 (we already cut the RC), but that means this is one of the first things up for inclusion in 3.5 in two weeks. If we can get sufficient attestations that this doesn't impact large react projects poorly by then, that'd be great. We're especially interested in super-large projects that already take close to or over a minute to build - those are the ones we're especially worried about.

I'll have @typescript-bot pack this so we can get a new package drop that's up-to-date with current master state.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Mar 18, 2019

Heya @weswigham, I've started to run the tarball bundle task on this PR at 5b9817b. You can monitor the build here. It should now contribute to this PR's status checks.

@weswigham
Copy link
Member Author

npm i https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/25480/artifacts?artifactName=tgz&fileId=AD3F52B0A194BF2FE87A3D83581F56859BB401F54FF3510A221B9AD939A7979402&fileName=typescript-3.4.0-insiders.20190318.tgz&api-version=5.0-preview.3 is the link/command for the latest drop.

@weswigham weswigham changed the title [WIP] Lookup return type of factory function for JSX expression return types Lookup return type of factory function for JSX expression return types Apr 16, 2019
@weswigham
Copy link
Member Author

@typescript-bot test this & @typescript-bot perf test this (though none of our perf tests contain JSX so i doubt they'll show anything useful)

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 4, 2019

Heya @weswigham, I've started to run the extended test suite on this PR at ebc8fce. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 4, 2019

Heya @weswigham, I've started to run the perf test suite on this PR at ebc8fce. You can monitor the build here. It should now contribute to this PR's status checks.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - master..29818

Metric master 29818 Delta Best Worst
Angular - node (v12.1.0, x64)
Memory used 313,217k (± 0.02%) 313,176k (± 0.02%) -40k (- 0.01%) 313,023k 313,266k
Parse Time 1.38s (± 0.53%) 1.39s (± 0.81%) +0.01s (+ 0.65%) 1.37s 1.42s
Bind Time 0.72s (± 0.69%) 0.73s (± 0.31%) +0.00s (+ 0.55%) 0.72s 0.73s
Check Time 3.97s (± 0.32%) 3.99s (± 0.78%) +0.03s (+ 0.71%) 3.94s 4.09s
Emit Time 5.15s (± 0.67%) 5.15s (± 0.65%) +0.00s (+ 0.10%) 5.10s 5.26s
Total Time 11.22s (± 0.30%) 11.27s (± 0.48%) +0.04s (+ 0.40%) 11.17s 11.38s
Monaco - node (v12.1.0, x64)
Memory used 342,083k (± 0.01%) 342,070k (± 0.01%) -13k (- 0.00%) 342,021k 342,226k
Parse Time 1.18s (± 0.47%) 1.18s (± 0.85%) -0.00s (- 0.08%) 1.16s 1.20s
Bind Time 0.67s (± 0.70%) 0.68s (± 1.95%) +0.01s (+ 1.19%) 0.67s 0.73s
Check Time 4.08s (± 0.39%) 4.09s (± 0.72%) +0.01s (+ 0.22%) 4.00s 4.14s
Emit Time 2.76s (± 0.48%) 2.77s (± 0.65%) +0.01s (+ 0.36%) 2.73s 2.81s
Total Time 8.70s (± 0.27%) 8.72s (± 0.61%) +0.02s (+ 0.28%) 8.58s 8.84s
TFS - node (v12.1.0, x64)
Memory used 298,982k (± 0.02%) 299,076k (± 0.02%) +94k (+ 0.03%) 298,975k 299,202k
Parse Time 0.90s (± 0.49%) 0.91s (± 0.93%) +0.01s (+ 1.00%) 0.89s 0.93s
Bind Time 0.62s (± 0.84%) 0.62s (± 0.80%) -0.00s (- 0.48%) 0.61s 0.63s
Check Time 3.62s (± 0.39%) 3.64s (± 0.44%) +0.02s (+ 0.55%) 3.60s 3.67s
Emit Time 2.85s (± 0.89%) 2.85s (± 0.80%) +0.01s (+ 0.28%) 2.81s 2.92s
Total Time 7.99s (± 0.37%) 8.02s (± 0.35%) +0.03s (+ 0.38%) 7.95s 8.10s
Angular - node (v8.9.0, x64)
Memory used 330,744k (± 0.02%) 330,802k (± 0.02%) +59k (+ 0.02%) 330,665k 330,903k
Parse Time 1.77s (± 0.40%) 1.78s (± 0.62%) +0.01s (+ 0.34%) 1.76s 1.80s
Bind Time 0.79s (± 1.15%) 0.79s (± 0.75%) +0.00s (+ 0.38%) 0.78s 0.81s
Check Time 4.71s (± 1.63%) 4.74s (± 1.29%) +0.03s (+ 0.72%) 4.60s 4.84s
Emit Time 5.94s (± 2.63%) 5.76s (± 2.74%) -0.18s (- 2.98%) 5.43s 6.23s
Total Time 13.21s (± 0.83%) 13.07s (± 0.96%) -0.14s (- 1.03%) 12.83s 13.39s
Monaco - node (v8.9.0, x64)
Memory used 358,800k (± 0.02%) 358,865k (± 0.02%) +65k (+ 0.02%) 358,780k 359,103k
Parse Time 1.43s (± 0.41%) 1.43s (± 0.46%) -0.00s (- 0.28%) 1.41s 1.44s
Bind Time 0.91s (± 1.67%) 0.91s (± 2.21%) -0.01s (- 0.88%) 0.87s 0.93s
Check Time 4.82s (± 1.45%) 4.87s (± 1.83%) +0.04s (+ 0.89%) 4.74s 5.07s
Emit Time 3.27s (± 5.17%) 3.17s (± 6.56%) -0.09s (- 2.85%) 2.83s 3.45s
Total Time 10.44s (± 1.21%) 10.38s (± 1.43%) -0.06s (- 0.57%) 10.05s 10.60s
TFS - node (v8.9.0, x64)
Memory used 314,194k (± 0.01%) 314,194k (± 0.01%) +0k (+ 0.00%) 314,122k 314,262k
Parse Time 1.13s (± 0.46%) 1.13s (± 0.51%) -0.00s (- 0.09%) 1.12s 1.14s
Bind Time 0.67s (± 1.43%) 0.66s (± 0.89%) -0.00s (- 0.15%) 0.65s 0.68s
Check Time 4.22s (± 0.57%) 4.24s (± 0.71%) +0.02s (+ 0.45%) 4.18s 4.29s
Emit Time 3.13s (± 0.88%) 3.13s (± 0.44%) +0.01s (+ 0.26%) 3.10s 3.17s
Total Time 9.14s (± 0.41%) 9.17s (± 0.46%) +0.02s (+ 0.26%) 9.07s 9.25s
Angular - node (v8.9.0, x86)
Memory used 187,378k (± 0.02%) 187,392k (± 0.03%) +14k (+ 0.01%) 187,274k 187,529k
Parse Time 1.71s (± 0.62%) 1.71s (± 0.55%) -0.00s (- 0.12%) 1.70s 1.74s
Bind Time 0.93s (± 2.03%) 0.93s (± 0.86%) +0.00s (+ 0.54%) 0.91s 0.94s
Check Time 4.32s (± 0.53%) 4.33s (± 0.68%) +0.01s (+ 0.21%) 4.28s 4.40s
Emit Time 5.63s (± 0.85%) 5.63s (± 1.49%) -0.00s (- 0.05%) 5.44s 5.79s
Total Time 12.60s (± 0.39%) 12.61s (± 0.72%) +0.01s (+ 0.07%) 12.38s 12.80s
Monaco - node (v8.9.0, x86)
Memory used 200,180k (± 0.02%) 200,240k (± 0.01%) +60k (+ 0.03%) 200,164k 200,296k
Parse Time 1.48s (± 0.57%) 1.49s (± 0.66%) +0.01s (+ 0.74%) 1.47s 1.52s
Bind Time 0.71s (± 1.15%) 0.72s (± 1.01%) +0.01s (+ 0.70%) 0.71s 0.74s
Check Time 4.65s (± 0.43%) 4.65s (± 0.62%) -0.00s (- 0.04%) 4.59s 4.71s
Emit Time 3.08s (± 0.71%) 3.09s (± 0.62%) +0.02s (+ 0.62%) 3.06s 3.14s
Total Time 9.92s (± 0.41%) 9.95s (± 0.50%) +0.03s (+ 0.30%) 9.87s 10.07s
TFS - node (v8.9.0, x86)
Memory used 176,250k (± 0.02%) 176,262k (± 0.02%) +12k (+ 0.01%) 176,202k 176,356k
Parse Time 1.19s (± 1.08%) 1.19s (± 0.61%) +0.00s (+ 0.17%) 1.17s 1.20s
Bind Time 0.63s (± 1.02%) 0.64s (± 1.19%) +0.00s (+ 0.63%) 0.62s 0.65s
Check Time 4.04s (± 0.47%) 4.06s (± 0.61%) +0.02s (+ 0.52%) 4.02s 4.13s
Emit Time 2.75s (± 1.68%) 2.73s (± 1.07%) -0.02s (- 0.58%) 2.68s 2.79s
Total Time 8.61s (± 0.56%) 8.62s (± 0.58%) +0.01s (+ 0.10%) 8.53s 8.77s
Angular - node (v9.0.0, x64)
Memory used 330,399k (± 0.02%) 330,449k (± 0.02%) +50k (+ 0.02%) 330,319k 330,560k
Parse Time 1.62s (± 0.59%) 1.63s (± 0.64%) +0.02s (+ 0.99%) 1.61s 1.66s
Bind Time 0.74s (± 0.95%) 0.74s (± 0.54%) -0.00s (- 0.00%) 0.73s 0.75s
Check Time 4.30s (± 0.63%) 4.33s (± 0.55%) +0.03s (+ 0.70%) 4.29s 4.41s
Emit Time 5.77s (± 2.13%) 5.81s (± 1.66%) +0.04s (+ 0.73%) 5.62s 5.99s
Total Time 12.43s (± 1.00%) 12.52s (± 0.71%) +0.09s (+ 0.73%) 12.31s 12.68s
Monaco - node (v9.0.0, x64)
Memory used 358,751k (± 0.02%) 358,752k (± 0.03%) +2k (+ 0.00%) 358,516k 358,954k
Parse Time 1.28s (± 0.45%) 1.29s (± 0.59%) +0.00s (+ 0.23%) 1.27s 1.30s
Bind Time 0.85s (± 0.53%) 0.85s (± 0.40%) +0.01s (+ 0.59%) 0.85s 0.86s
Check Time 4.68s (± 0.65%) 4.70s (± 0.48%) +0.02s (+ 0.34%) 4.65s 4.74s
Emit Time 3.29s (± 0.64%) 3.30s (± 0.60%) +0.00s (+ 0.12%) 3.26s 3.34s
Total Time 10.10s (± 0.47%) 10.13s (± 0.44%) +0.03s (+ 0.31%) 10.04s 10.21s
TFS - node (v9.0.0, x64)
Memory used 314,062k (± 0.01%) 314,056k (± 0.01%) -7k (- 0.00%) 314,023k 314,120k
Parse Time 1.00s (± 0.60%) 1.01s (± 0.47%) +0.00s (+ 0.20%) 1.00s 1.02s
Bind Time 0.61s (± 0.56%) 0.61s (± 0.85%) -0.00s (- 0.33%) 0.60s 0.62s
Check Time 4.16s (± 1.33%) 4.21s (± 2.00%) +0.05s (+ 1.30%) 4.07s 4.39s
Emit Time 3.03s (± 2.15%) 2.98s (± 2.46%) -0.05s (- 1.55%) 2.81s 3.06s
Total Time 8.81s (± 0.34%) 8.81s (± 0.49%) +0.00s (+ 0.03%) 8.72s 8.92s
Angular - node (v9.0.0, x86)
Memory used 187,479k (± 0.02%) 187,534k (± 0.03%) +56k (+ 0.03%) 187,456k 187,682k
Parse Time 1.53s (± 0.36%) 1.54s (± 0.61%) +0.02s (+ 0.98%) 1.52s 1.57s
Bind Time 0.86s (± 1.21%) 0.86s (± 1.05%) -0.01s (- 0.81%) 0.84s 0.88s
Check Time 4.03s (± 0.42%) 4.01s (± 0.46%) -0.01s (- 0.35%) 3.96s 4.05s
Emit Time 5.36s (± 0.97%) 5.37s (± 0.95%) +0.01s (+ 0.21%) 5.32s 5.56s
Total Time 11.78s (± 0.49%) 11.79s (± 0.44%) +0.01s (+ 0.08%) 11.69s 11.95s
Monaco - node (v9.0.0, x86)
Memory used 200,207k (± 0.02%) 200,282k (± 0.03%) +74k (+ 0.04%) 200,156k 200,374k
Parse Time 1.30s (± 0.51%) 1.30s (± 0.89%) -0.00s (- 0.00%) 1.28s 1.34s
Bind Time 0.64s (± 0.73%) 0.64s (± 0.73%) 0.00s ( 0.00%) 0.63s 0.65s
Check Time 4.49s (± 0.64%) 4.50s (± 0.41%) +0.01s (+ 0.27%) 4.47s 4.54s
Emit Time 3.01s (± 0.63%) 3.02s (± 1.55%) +0.02s (+ 0.53%) 2.96s 3.20s
Total Time 9.43s (± 0.46%) 9.46s (± 0.51%) +0.03s (+ 0.28%) 9.37s 9.61s
TFS - node (v9.0.0, x86)
Memory used 176,328k (± 0.02%) 176,328k (± 0.02%) 0k ( 0.00%) 176,230k 176,408k
Parse Time 1.02s (± 0.89%) 1.02s (± 0.66%) +0.00s (+ 0.29%) 1.01s 1.04s
Bind Time 0.57s (± 0.83%) 0.57s (± 1.32%) +0.00s (+ 0.35%) 0.56s 0.60s
Check Time 3.94s (± 0.97%) 3.92s (± 0.36%) -0.01s (- 0.36%) 3.89s 3.94s
Emit Time 2.69s (± 0.67%) 2.69s (± 0.98%) -0.00s (- 0.11%) 2.62s 2.74s
Total Time 8.23s (± 0.70%) 8.21s (± 0.34%) -0.01s (- 0.18%) 8.16s 8.29s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-142-generic
Architecturex64
Available Memory16 GB
Available Memory1 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
  • node (v9.0.0, x64)
  • node (v9.0.0, x86)
Scenarios
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Angular - node (v9.0.0, x64)
  • Angular - node (v9.0.0, x86)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • Monaco - node (v9.0.0, x64)
  • Monaco - node (v9.0.0, x86)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
  • TFS - node (v9.0.0, x64)
  • TFS - node (v9.0.0, x86)
Benchmark Name Iterations
Current 29818 10
Baseline master 10

@weswigham
Copy link
Member Author

Yeah, there was an issue in master that merged into here and blocked the build. You can always clone and build locally; but I can try to sync and build again.

@butchler
Copy link

butchler commented Nov 3, 2019

I was able to build and run the branch locally. I got very similar results to #29818 (comment) (I need to increase memory to run it successfully, I get many errors, and it took longer).

With this branch:

$ node --max-old-space-size=4096 ../TypeScript/built/local/tsc.js --extendedDiagnostics

...lots of errors that don't show up normally...

Found 1080 errors.

Files:                        2873
Lines:                      323202
Nodes:                         NaN
Identifiers:                   NaN
Symbols:                   8876411
Types:                     1194946
Memory used:              3471407K
Assignability cache size:   955521
Identity cache size:        235563
Subtype cache size:         540123
I/O Read time:               0.24s
Parse time:                  1.59s
Program time:                3.49s
Bind time:                   1.52s
Check time:                118.40s
transformTime time:          3.34s
Source Map time:             1.38s
commentTime time:            1.50s
I/O Write time:              1.49s
printTime time:             15.40s
Emit time:                  15.40s
Total time:                138.81s

With TypeScript 3.5.3:

$ tsc --extendedDiagnostics
Files:                       2872
Lines:                     321623
Nodes:                        NaN
Identifiers:                  NaN
Symbols:                   998848
Types:                     483509
Memory used:              978699K
Assignability cache size:  280204
Identity cache size:         4124
Subtype cache size:         58999
I/O Read time:              0.23s
Parse time:                 1.52s
Program time:               3.41s
Bind time:                  1.30s
Check time:                26.12s
transformTime time:         2.59s
Source Map time:            0.64s
commentTime time:           0.91s
I/O Write time:             1.22s
printTime time:            10.73s
Emit time:                 10.73s
Total time:                41.55s

@weswigham weswigham added the Experiment A fork with an experimental idea which might not make it into master label Jan 2, 2020
@cruhl
Copy link

cruhl commented Jan 8, 2020

I am not sure what the status of this is, but since it's required to fix these issues...

DefinitelyTyped/DefinitelyTyped#33908
DefinitelyTyped/DefinitelyTyped#20544
apollographql/react-apollo#3314
DefinitelyTyped/DefinitelyTyped#18912

...I'm wondering if we can get a general update?

@TylorS
Copy link

TylorS commented Feb 14, 2020

I've been working on a virtual-dom library that uses Generator Functions to represent Algebraic Effects for asynchronously rendering components. I'd find it very helpful to be able to use the JSX factory return type to properly type values and not require all of my generics to be filled in with any (e.g. JSX.Element = VNode<any>.

I'd like to help see this across the finish line if there's anything helpful I could still do at this point.

@weswigham
Copy link
Member Author

weswigham commented Feb 15, 2020

Well, so this works, but it has 2 problems:

  1. Most consumers do not expect the very specific type the jsx factory function actually returns. Usually, this manifests in reassignments, where
let a = <div></div>;
a = <img />;

ends up being an error because rather than both being JSX.Element, the first assignment makes a a React.ReactElement<HTMLDivElement>, while the second line is a React.ReactElement<HTMLImageElement>. This is, unfortunately, a breaking change we'd force on people. It's not hard to fix (annotate a with the more vague JSX.Element yourself), but could be frustrating. That break reduces the appetite to take this change a bit.

  1. Performance is terrible. Like beyond bad. This makes every jsx tag tree in your program into a series of nested generic context sensitive function calls (and most jsx apps have a lot of nested tags!). That's just about the worst-case scenario for the type checker. If we could make nested context sensitive function calls much more performant to check, it'd go a long way towards making merging this feasible.

@TylorS
Copy link

TylorS commented Feb 15, 2020

Hey @weswigham, thanks for the reply.

Excuse any of my ignorance, but would it be possible for a solution to 1 be to place this feature behind a new JSX-related compiler flag? Maybe something like jsxFactoryReturnTypes: boolean? Personally, I'd prefer to always have the most accurate types.

As for 2, I'll have to get myself more acquainted with how this functions right now before. Have there been any prior discussions on what optimizations remain to be made?

@reverofevil
Copy link

This performance (1kLoC/s) sounds like fair price for having JSX properly typed. In my personal project I have to use custom h() syntax by hand, which compiles as slow as JSX in this branch, is extremely ugly and tedious to type. If there are no untold reasons this PR is thought to be (inevitably subjectively) bad for further TS development (like small potential user base compared to cost of support; or someone having a vision of a better implementation of typechecker that both doesn't exhibit this behavior and doesn't break most of the code), I see no barriers to putting this code into the closest release.

AFAI understand, performance is affected a lot by number of overloads, and it can get way better if library users choose a subset of those, because barely any real-life projects require all the tags from <abbr> to <wbr>.

If the performance problem is still an issue after that, it's always possible to resort to separate compilation (restrict dependencies to be a tree, build js/d.ts pair from each ts file with a set d.ts for its imports), even though I haven't seen this approach used anywhere.

I can try it on a large project at job, if you still need more input on its performance, but I suspect it won't be able to fit in memory.

@cshaa
Copy link

cshaa commented Apr 12, 2020

Wouldn't it be possible to release this feature as optional in an upcoming version? As @TylorS says, the compiler flag sounds like a good solution. Every time I work with TypeScript and any Virtual DOM library, I find myself needing this feature. And every time it's terribly frustrating to know it's already implemented and I just can't use it.

Thank you for your work on this feature, but please consider merging it again. JSX is an awesome concept, but without type-checking it's as unfriendly as pure JavaScript without TS.

EDIT: I think many of the performance issues might be mitigated by skillfully typing createElement. But it's not easy to experiment with it without this feature merged at least in a beta.

EDIT 2: It should be noted that needing typed JSX in React should be a relative edge case. The philosophy of React is that parent nodes shouldn't do any magic with their children, the children should always decide for themselves. That, however, doen't mean there aren't valid uses for typed JSX in React. And, most importantly, in other non-React libraries that use JSX, there isn't this kind of precedent, and limiting the type of your child nodes is a totally reasonable thing to do.

@bela53
Copy link

bela53 commented Apr 23, 2020

I would like to test this feature as well. What I already figured out (is this the right approach?):

npm i https://github.com/weswigham/TypeScript.git#jsx-element-realtypes

, which uses jsx-element-realtypes branch from the fork to run TS build locally.

Is there also a React types side of things, so we can play around with custom JSX.Element types, component return types etc.? Of course, the current @types/react will reflect current limitations like return type JSX.Element | null for Function components.

I think, if there would be a more detailed manual, a starter or even an experimental TS flag, more people would be able to test and contribute benchmark results.

@bluepnume
Copy link

bluepnume commented May 12, 2020

Agreed, it would be great to have this behind an experimental flag. I'm still using Flow, but I'd love to take the opportunity to switch to TypeScript -- this is pretty much the only thing blocking me, since I'm extensively using jsx with custom renderers, using https://github.com/krakenjs/jsx-pragmatic

@samvv
Copy link

samvv commented Dec 18, 2020

Sorry for the noise, but just adding that this is a really useful feature that I'd really like to see merged. In the meantime I'll be using this branch and see how far I can go. I really like @TylorS's idea of putting it under a seperate compiler option. Would this be feasible?

@canonic-epicure
Copy link

A friendly bump. This is a quality of life feature, very much anticipated. Since there's a working PR for it already, why holding it back?

Hiding it behind a flag sounds like a good idea.

@seansfkelley
Copy link

@weswigham you said in #29818 (comment):

Performance is terrible. Like beyond bad. ... If we could make nested context sensitive function calls much more performant to check, it's go a long way towards making merging this feasible.

Is there a tracking issue or something of the sort for that work? I'm trying to get a sense for what would be involved in getting this over the finish line.

FWIW, the use-case I have for this is to strictly-type XML in accordance with a specific schema.

@TylorS
Copy link

TylorS commented Jan 21, 2022

I'd like to make another bump here on this feature. In 2022, this is the #1 feature I personally feel is still missing from TypeScript. I've been using it for 6+ years and it's gotten soooo much better but I keep coming back to this thread and hoping to have seen movement.

Primarily I've been wanting to be able to keep track of the resources that a Component needs to be able to run, as in performing dependency injection. I'd hope to be able to aggregate all the requirements "up" to the entry point of my applications and provide all the necessary resources there based on the environment (e.g. node vs browser) to write a component that runs easily in each all while not being tied to any particular view/templating library. I've circumnavigated it in multiple ways over time, like @polkovnikov-ph mentioned with writing hyperscript manually which is often tedious, and to avoid templates requiring dependencies altogether and lifting requirements "up" in various other ways which often leads to more boilerplate to nest or compose components, but I always come back to thinking it'd just be great to have JSX capable of supporting generics itself and utilize a diff like React does to mount/unmount components as needed.

Is there any hope of seeing this feature make its way into TypeScript or is the performance overhead more likely to be too much to overcome?

@reverofevil
Copy link

If we could make nested context sensitive function calls much more performant to check, it's go a long way towards making merging this feasible.

Three years after, I still don't understand this consequent. Making it work (under a flag) doesn't necessarily require good performance. Whether it could be improved at some point in future or not doesn't really matter, because some of us do need typed JSX anyway.

Maybe the actual issue is it's unclear how exactly that flag should be implemented, so that there is no need to provide separate typings for libraries for different JSX typechecker behaviors?

@sandersn
Copy link
Member

This experiment is pretty old, so I'm going to close it to reduce the number of open PRs.

@sandersn sandersn closed this May 24, 2022
@reverofevil
Copy link

@sandersn

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experiment A fork with an experimental idea which might not make it into master
Projects
None yet