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
When possible, remove fully-excluded constituents of a union-constrained type parameter from the false arm of a conditional type #48710
Comments
Simpler: type IsB<T extends "B"> = unknown;
type F<T extends "A" | "B"> = T extends "A" ? unknown : IsB<T>; In the general case, it's not sound to narrow the false arm of a conditional type. When the check type fully subsumes one of the constraint's union constituents we could, but that logic just isn't present right now. Regardless, the workaround is straightforward. |
Thanks for the suggestion, but the simpler version has 2 issues
|
Since this is tagged as "awaiting more feedback", I'll quickly leave some (what I believe are simpler, - or at least easier to understand) examples here, from my issue, which was marked as duplicate. Adding "special cases" to a
|
Just documenting the workarounds since I'm confirming they exist anyway: type ObjVal<Key extends ObjKey> = Key extends "specialCase" ? SpecialCase : Obj[Exclude<Key, "specialCase">];
// Make them different so we can check them
type A = {x: "is x";};
type B = {y: "is y";};
type Both = A | B;
type X1<T extends Both> = T extends { x: infer U } | { y: infer U } ? U : never;
// Tests, all ok
type T1 = X1<A>;
type T2 = X1<B>;
type T3 = X1<A | B>; |
type X1<T extends Both> = T extends Partial<Record<"x" | "y", infer U>> ? U : never; is also possible but probably worse |
I actually did that, but it became tedious quickly, after needing to add multiple special cases. Especially since the key name has to be typed out twice, but that's nitpicking. Anyhow, I'm not sure if it has been mentioned before, but I find this a bit nicer: interface Obj { foo1: number; foo2?: number; bar1: string; bar2?: string; }
type SpecialCase1 = { id_1: number };
type SpecialCase2 = { id_2: number };
type ObjKey = keyof Obj | "specialCase1" | "specialCase2";
type ObjVal<Key extends ObjKey> = Key extends keyof Obj
? Obj[Key]
: Key extends "specialCase1"
? SpecialCase1
: Key extends "specialCase2"
? SpecialCase2
: never; |
Bug Report
π Search Terms
narrow type, mapped type, union
π Version & Regression Information
Tested on latest version 4.6.2
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
TS doesn't narrow the type and thus throws an error.
π Expected behavior
When generic is constrained by a union type (e.g.
A | B
) then the conditional type should narrow the type when checking against one of those types from the union.T extends A ? <here we know it must be A type> : <here we know it must be B type>
The text was updated successfully, but these errors were encountered: