tools
tools copied to clipboard
feat: Support extends constraints on infer type
Summary
Part of #2400
This PR is initial implementation for "extends constraints on infer type" released in TS.4.7.
Test Plan
I add some parser tests and confirmed the prettier tests are almost passed. The only following case is not passed, so I'm currently considering about how to pass it.
type X9<U, T> = T extends (infer U extends number ? U : T ) ? U : T
Deploy Preview for docs-rometools ready!
Built without sensitive environment variables
| Name | Link |
|---|---|
| Latest commit | f5c64b547ff0f375abffdca55e2864728cafeebf |
| Latest deploy log | https://app.netlify.com/sites/docs-rometools/deploys/63aec6217424ba000a5e3852 |
| Deploy Preview | https://deploy-preview-4018--docs-rometools.netlify.app/playground |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
To edit notification comments on pull requests, go to your Netlify site settings.
@MichaReiser Thank you for your review! I updated codes based on your comments. Currently, I struggle with two edge case. The first case (EdgeCase1) is that it is not sufficient for the parser to check one token ahead. The second case (EdgeCase2) is that parse failed because of removing parentheses. I would appreciate if you could give me some advice.
type EdgeCase1<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0;
type EdgeCase2<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;
Log
✖ expected `?` but instead found `;`
> 1 │ type EdgeCase2<T> = T extends (...a: any[]) => infer R extends string ? R : never;
│ ^
2 │
@MichaReiser Thank you for your review! I updated codes based on your comments. Currently, I struggle with two edge case. The first case (EdgeCase1) is that it is not sufficient for the parser to check one token ahead. The second case (EdgeCase2) is that parse failed because of removing parentheses. I would appreciate if you could give me some advice.
type EdgeCase1<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; type EdgeCase2<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;Log
✖ expected `?` but instead found `;` > 1 │ type EdgeCase2<T> = T extends (...a: any[]) => infer R extends string ? R : never; │ ^ 2 │
I looked into this more closely because it wasn't clear to me why the parsing is failing, and I created a draft PR that uses try_parse and allows conditional places in a few more places. In my opinion it would be good to explore if the DisallowConditionalTypes flag would be moved into a new TypesContext that works similar to ExpressionContext and is passed down everywhere where we parse types. It makes it easier to debug and reason about the code (with the downside of it needing to be passed explicitly)
Case 1
You can use the try_parse function for speculative parsing when a fixed lookahead isn't sufficient (as it is in this case because you need to look if the type is followed by a ? token and the type could be of multiple tokens).
Case 2
Not entirely sure but I think the issue here is that you missed to allow conditional types.
!bench_parser
Thanks for updating the PR.
Do you plan to refactor the code to use a TypeContext instead of extending the ParserState?
There are a few tests failing that should pass
type Equals = A extends () => B extends C ? D : E ? F : G;type Equals<A, B, C, D, E, F, G> = A extends (x: B extends C ? D : E) => 0 ? F : G;This one fails for typescript too but should be easy to fix by wrapping theparse_ts_typecall inparse_ts_parenthesized_typewith anallow()
Parser Benchmark Results
group main pr
----- ---- --
parser/big5-added.json 1.02 255.6±8.00µs 66.1 MB/sec 1.00 251.6±9.27µs 67.1 MB/sec
parser/canada.json 1.00 131.7±5.82ms 16.3 MB/sec 1.02 134.5±7.79ms 16.0 MB/sec
parser/checker.ts 1.01 165.3±5.63ms 15.7 MB/sec 1.00 163.8±5.31ms 15.9 MB/sec
parser/compiler.js 1.00 95.1±2.44ms 11.0 MB/sec 1.01 95.8±2.85ms 10.9 MB/sec
parser/d3.min.js 1.01 57.7±2.46ms 4.5 MB/sec 1.00 57.1±2.48ms 4.6 MB/sec
parser/db.json 1.01 6.4±0.20ms 27.9 MB/sec 1.00 6.3±0.22ms 28.3 MB/sec
parser/dojo.js 1.01 4.7±0.11ms 14.7 MB/sec 1.00 4.6±0.13ms 14.8 MB/sec
parser/eucjp.json 1.01 424.7±12.61µs 92.2 MB/sec 1.00 419.5±16.00µs 93.4 MB/sec
parser/ios.d.ts 1.01 142.5±5.10ms 13.1 MB/sec 1.00 141.0±4.43ms 13.2 MB/sec
parser/jquery.min.js 1.02 14.8±0.50ms 5.6 MB/sec 1.00 14.5±0.46ms 5.7 MB/sec
parser/math.js 1.01 115.4±4.57ms 5.6 MB/sec 1.00 114.8±3.98ms 5.6 MB/sec
parser/package-lock.json 1.00 2.6±0.09ms 52.9 MB/sec 1.00 2.6±0.07ms 53.1 MB/sec
parser/parser.ts 1.02 3.3±0.09ms 14.6 MB/sec 1.00 3.3±0.09ms 14.8 MB/sec
parser/pixi.min.js 1.03 73.4±2.87ms 6.0 MB/sec 1.00 71.2±2.24ms 6.2 MB/sec
parser/react-dom.production.min.js 1.00 20.3±1.15ms 5.7 MB/sec 1.01 20.5±1.08ms 5.6 MB/sec
parser/react.production.min.js 1.04 1040.6±54.70µs 5.9 MB/sec 1.00 1005.2±35.11µs 6.1 MB/sec
parser/router.ts 1.00 1308.9±33.94µs 23.5 MB/sec 1.00 1307.9±45.11µs 23.5 MB/sec
parser/tex-chtml-full.js 1.01 155.4±4.52ms 5.9 MB/sec 1.00 153.8±4.54ms 5.9 MB/sec
parser/three.min.js 1.02 81.0±2.80ms 7.3 MB/sec 1.00 79.7±2.73ms 7.4 MB/sec
parser/typescript.js 1.01 650.6±12.95ms 14.6 MB/sec 1.00 647.1±12.37ms 14.7 MB/sec
parser/vue.global.prod.js 1.00 25.1±1.20ms 4.8 MB/sec 1.04 26.1±1.23ms 4.6 MB/sec
@MichaReiser Thank you for your reviews and i'm so sorry for a late response. I really appreciate the time you spent on this. I learned a lot about how to handle parser contexts and use try_parse from your PR.
I would like to do the refactoring and fix the failing tests if possible, but it will be the day after tomorrow before I can start. This task might have been a bit difficult for me. Therefore, I am willing to have you continue the task on your end.
@MichaReiser
Thank you for your reviews and i'm so sorry for a late response. I really appreciate the time you spent on this. I learned a lot about how to handle parser contexts and use try_parse from your PR.
I would like to do the refactoring and fix the failing tests if possible, but it will be the day after tomorrow before I can start. This task might have been a bit difficult for me. Therefore, I am willing to have you continue the task on your end.
That's alright. We're all taking a few days off. Enjoy the holidays
There are a few tests failing that should pass
I could fix these tests and pass all prettier tests!
Do you plan to refactor the code to use a TypeContext instead of extending the ParserState?
I tried to refactor in a few days and made PR https://github.com/nissy-dev/tools/pull/6. If the PR is not so different from your thought, I will merge it into this PR and continue to review.
There are a few tests failing that should pass
I could fix these tests and pass all prettier tests!
Do you plan to refactor the code to use a TypeContext instead of extending the ParserState?
I tried to refactor in a few days and made PR nissy-dev#6. If the PR is not so different from your thought, I will merge it into this PR and continue to review.
This PR and your other PR looks good. The only thing that we need to be careful about is to make sure to pass context through correctly and only use TypeContext::default in positions where a type starts a complete new context (because it is parenthesized)
The only thing that we need to be careful about is to make sure to pass context through correctly and only use TypeContext::default in positions where a type starts a complete new context (because it is parenthesized)
If the scope of the refactoring is up to making sure the context is passed correctly, I think it is better to separate PR about the refactoring task. This is because there are too many functions which the context should be passed and this refactoring affects many logic.
And then, it is really hard for me to pass context through correctly. I tried, but I couldn't do that. I would like you to do this refactoring on your end if possible.
That sounds good to me. Thank you @nissy-dev for another excellent parser contribution!
!bench_parser
Parser Benchmark Results
group main pr
----- ---- --
parser/big5-added.json 1.02 193.1±0.55µs 87.5 MB/sec 1.00 189.4±0.30µs 89.2 MB/sec
parser/canada.json 1.01 88.3±2.16ms 24.3 MB/sec 1.00 87.8±2.78ms 24.4 MB/sec
parser/checker.ts 1.00 114.7±1.49ms 22.7 MB/sec 1.02 117.3±1.59ms 22.2 MB/sec
parser/compiler.js 1.00 65.9±0.86ms 15.9 MB/sec 1.04 68.3±0.71ms 15.3 MB/sec
parser/d3.min.js 1.00 40.3±0.32ms 6.5 MB/sec 1.05 42.3±0.35ms 6.2 MB/sec
parser/db.json 1.00 4.8±0.02ms 37.1 MB/sec 1.00 4.9±0.02ms 36.9 MB/sec
parser/dojo.js 1.00 3.7±0.01ms 18.8 MB/sec 1.05 3.8±0.00ms 17.9 MB/sec
parser/eucjp.json 1.00 329.7±0.28µs 118.8 MB/sec 1.00 329.6±0.19µs 118.8 MB/sec
parser/ios.d.ts 1.00 95.7±1.19ms 19.5 MB/sec 1.04 99.6±1.77ms 18.7 MB/sec
parser/jquery.min.js 1.00 11.0±0.03ms 7.5 MB/sec 1.05 11.6±0.03ms 7.1 MB/sec
parser/math.js 1.00 78.1±0.84ms 8.3 MB/sec 1.05 82.2±0.86ms 7.9 MB/sec
parser/package-lock.json 1.00 2.0±0.01ms 68.3 MB/sec 1.00 2.0±0.01ms 68.5 MB/sec
parser/parser.ts 1.00 2.6±0.01ms 18.8 MB/sec 1.04 2.7±0.01ms 18.0 MB/sec
parser/pixi.min.js 1.00 50.5±0.70ms 8.7 MB/sec 1.03 52.0±0.73ms 8.4 MB/sec
parser/react-dom.production.min.js 1.00 14.7±0.03ms 7.8 MB/sec 1.05 15.5±0.07ms 7.4 MB/sec
parser/react.production.min.js 1.00 737.0±9.81µs 8.3 MB/sec 1.06 777.8±2.23µs 7.9 MB/sec
parser/router.ts 1.00 1001.8±1.71µs 30.7 MB/sec 1.04 1046.3±6.15µs 29.4 MB/sec
parser/tex-chtml-full.js 1.00 110.0±2.13ms 8.3 MB/sec 1.00 110.6±1.03ms 8.2 MB/sec
parser/three.min.js 1.00 54.6±0.63ms 10.8 MB/sec 1.05 57.3±0.64ms 10.2 MB/sec
parser/typescript.js 1.00 438.1±4.36ms 21.7 MB/sec 1.04 456.4±5.08ms 20.8 MB/sec
parser/vue.global.prod.js 1.00 17.9±0.07ms 6.7 MB/sec 1.08 19.2±0.11ms 6.3 MB/sec