Not planned
Description
🔎 Search Terms
mapped types templates contravariant inference
🕗 Version & Regression Information
- This changed between versions 4.1.5 and 4.2.3.
- This is the behavior in every version I tried.
⏯ Playground Link
💻 Code
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
function test<T>(value: T)
{
type I = UnionToIntersection<
{ a: number }
| { b: number }
| (T extends number ? { c: T } : { c: T })
>;
let i : I = null as any;
i.a = 1; // With c defined, i.a is available only up to version 4.1.5. Afterwards, it breaks.
i.b = 1; // Same for i.b.
i.c = value;
}
🙁 Actual behavior
The non-generic dependent properties were not available.
🙂 Expected behavior
At least the non-generic dependent properties to be available. Ideally, c
should have been available too and value
should have been assignable to it, but that's less "expected" than the first part.
Additional information about the issue
It completely breaks more complex mapped types that used to work up to 4.1.5. The conditional generic type was still not available, but it was better than nothing.
If the previous behaviour cannot be restored, perhaps there's a way to detect that you're dealing with a generic type which will be deferred, and allow the programmer to decide what to do with it?
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
jcalz commentedon Nov 8, 2023
You might consider coming up with an example that doesn't depend on
UnionToIntersection
since that tends to get issues closed: #43077 (comment); #56185; see #29594 (comment) also. Can you reproduce the basic issue with a less problematic use of contravariant inference?rzvc commentedon Nov 8, 2023
@jcalz, not sure if this is what you meant by less problematic, but would this do it?
https://tsplay.dev/w2QOrW
jcalz commentedon Nov 8, 2023
I imagine the type should have some obvious real-world utility for a use case the TS team is interested in supporting, but I can't say what that is on first glance. 🤷♂️
rzvc commentedon Nov 8, 2023
@jcalz, well, that kinda pulls
UnionToIntersection
back into the conversation, because it's useful when you have to break a type apart with something like this, and then put the result back together:fatcerberus commentedon Nov 9, 2023
I’m confused why you’re writing
T extends U ? V : V
(presumably this is just to get the distributive behavior?) instead of something likeT extends unknown ? V : never
Although in the case of
Remap
there’s seemingly no reason to write that conditional type at all sinceT[K] extends …
is not distributive…rzvc commentedon Nov 9, 2023
@fatcerberus,
Remap
is just an example, not a real world thing. I wrote it to demonstrate the type of mapping with conditional types, that would require contravariant inference to work when one of the properties of the type being mapped has a generic type.In its extends clause, I'm not looking for enabling the distributive behaviour, but to show that the types I'm having problems with are doing some
extends
logic in the remapping process, which is a necessary ingredient to break inference.typescript-bot commentedon Nov 12, 2023
This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.