Closed
Description
TypeScript Version: 3.4.0-dev.201xxxxx
Search Terms: distributive conditional types, 1-tuple
Code
// Here are a couple types that will populate a discriminated union
interface UnionA {
type: 'a';
foo: boolean;
}
interface UnionB {
type: 'b';
bar: number;
}
// This is the discriminated union
type Union = UnionA | UnionB;
// Here is a type that is like those in Union, but a little more general
interface MyDefault {
type: string;
/* ... more default properties */
}
// The goal is to have a type whose generic parameter which can identify a type by the discriminant from
// Union, and if one isn't found, resolves to MyDefault
// First let's define a helper that will either resolve to T when its not the empty union, or
// Default when it is the empty union. Notice that the 1-tuple wrapper is used to avoid distribution.
type FallbackWhenBottom<T, Default> = [T] extends [never] ? Default : T;
// Now, this completes the goal.
type UnionByTypeWithDefault<T extends string> = FallbackWhenBottom<Extract<Union, { type: T }>, MyDefault>
// Let's test it out
type Test = UnionByTypeWithDefault<'a'>; // success: Test === UnionA
type Test2 = UnionByTypeWithDefault<'c'>; // fail: Test2 === never, expected Test2 === MyDefault
// DARN! Let's try to pick apart Test2 the way we think it should be evaluated
// This should be evaluated first (rem, FallbackWhenBottom was defined not to be distributive)
type Test3<T> = Extract<Union, { type: T }>;
type Test4 = Test3<'c'> // success: Test4 === never
// Then that should be substituted into FallbackWhenBottom
type Test5 = FallbackWhenBottom<never, MyDefault> // success: Test5 === MyDefault
// It seems like FallbackWhenBottom *is* behaving as distributive, as that's the only explanation
// for how Test2 could be never - T as never is being treated as the empty union. The 1-tuple should be preventing this ([never]), but it's not.
Expected behavior:
Test2
should evaluate to MyDefault
Actual behavior:
Test2
is evaluated to never
Playground Link: Link
Metadata
Metadata
Assignees
Labels
No labels