Add missing conditional type relationships #24821
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Also:
keyof
reverse inference for non-string literal types (so an inference from0
tokeyof T
produces a nonempty object forT
).true
andfalse
conditional branches, and for a greater variety of references (more than simply a bare reference or index - now substitutions forkeyof
, for example, would be allowed) This has two implications:keyof T extends string ? keyof T : never
now has the additional constraint onkeyof T
in the true branch correctly tracked.keyof T extends string ? never : keyof T
has the negation of its constraint in the false branch tracked (yes, that means conditional types now function as real negated types)An example:
Note that the above are the critical usecases, since they're how we're telling people to workaround the keyof changes in 2.9 (hence the bundled keyof inference fix).
Fixes #24560
@ahejlsberg This is what I was talking about with you earlier. 590e4d5 has just the new relationships and the true-branch-only (as without the following two commits, the false branch would produce false positives) conditional-reverse inference checking implementation (less some bugfixes in the third commit), while 88623ad and aa2709f are about improving substitution types to be able to track the negation of a constraint in addition to the constraint itself, then enabling the
false
branch relation.As an aside, I still don't create substitution types everywhere (though I certainly applied them to more locations) - generally, the usage of any generic type (or thing which can contain one) should potentially be a substitution type (which can then be removed by instantiation until it gets potentially reapplied later by relationship checking), so it can be matched on. Eg,
{ x: T } extends { x: string } ? { y: { x: T } } : never
should be able to find{ y: { x: (T & string) } }
assignable to it whenT extends number | string
. This really brings home how substitution types are really just emulating flow control in the typespace.