Defer resolution of true and false branches in conditional types#31354
Defer resolution of true and false branches in conditional types#31354ahejlsberg merged 7 commits intomasterfrom
Conversation
|
@typescript-bot test this |
|
Heya @ahejlsberg, I've started to run the extended test suite on this PR at bb9c5c9. You can monitor the build here. It should now contribute to this PR's status checks. |
|
@typescript-bot run dt |
|
Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at bb9c5c9. You can monitor the build here. It should now contribute to this PR's status checks. |
|
There are definitely significantly fewer types being created when the true and false branches are deferred. Compiling Compiling Compiling Compiling |
|
Probably fixes #31341 too. |
|
@ahejlsberg we should be able to defer the simplification to assignability checking, similar to indexed accesses, to keep the fixed use-cases functional. |
|
@ahejlsberg #31374 is open with what I suggested - perf impact (compared to this PR as-is) in |
…lification Simplify conditionals upon comparison, rather than instantiation
|
@typescript-bot test this |
|
Heya @ahejlsberg, I've started to run the extended test suite on this PR at 066e4b6. You can monitor the build here. It should now contribute to this PR's status checks. |
|
@typescript-bot run dt |
|
Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 066e4b6. You can monitor the build here. It should now contribute to this PR's status checks. |
| Type 'keyof B' is not assignable to type '"valueOf"'. | ||
| Type 'string | number | symbol' is not assignable to type '"valueOf"'. | ||
| Type 'string' is not assignable to type '"valueOf"'. | ||
| Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf" | keyof A'. |
There was a problem hiding this comment.
did keyof A expand into... itself? o.O
There was a problem hiding this comment.
In the first keyof A, A is a substitution type. It then gets expanded into keyof (A & string) which becomes the union that ends in keyof A where A is the actual type variable. Not ideal, but neither was the prior error message.
| return getSimplifiedType(trueType, writing); | ||
| } | ||
| else if (isIntersectionEmpty(checkType, extendsType)) { // Always false | ||
| return neverType; |
There was a problem hiding this comment.
Why wasn't this just a Debug.fail?
There was a problem hiding this comment.
Because it can happen and is perfectly fine when it does. Or am I misunderstanding your question?
There was a problem hiding this comment.
BTW, the comment "Always false" here refers to when the condition of the conditional type is known to always be false. It doesn't imply that the if condition is always false.
This PR restores our previous behavior of deferring resolution of the true and false branches of conditional types. This fixes the performance regression we were seeing with statement completion in projects using
styled-components(performance is now similar to 3.3).Because resolution of the true and false branches is deferred, simplifications of conditional types of the formT extends xxx ? T : neverandT extends xxx ? never : Tonly occur when the actual declarations of the conditional types are written with identical types in theTposition and typeneverin the other position (i.e. simplification doesn't occur when conditional types only match the pattern following instantiation). This shouldn't matter in practice as the types we really care about,ExcludeandExtract, follow the pattern. For example, #28748 is still fixed.EDIT: Conditional type simplification now takes place in
getSimplifiedTypeand we simplify to the same extent as before, so the above comment no longer applies.Fixes #31302.
Fixes #31341.