Skip to content

Cannot escape distribution of conditional type properly #30020

Description

@aoberoi

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 unioninterfaceUnionA{type: 'a';foo: boolean;}interfaceUnionB{type: 'b';bar: number;}// This is the discriminated uniontypeUnion=UnionA|UnionB;// Here is a type that is like those in Union, but a little more generalinterfaceMyDefault{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.typeFallbackWhenBottom<T,Default>=[T]extends[never] ? Default : T;// Now, this completes the goal.typeUnionByTypeWithDefault<Textendsstring>=FallbackWhenBottom<Extract<Union,{type: T}>,MyDefault>// Let's test it outtypeTest=UnionByTypeWithDefault<'a'>;// success: Test === UnionAtypeTest2=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)typeTest3<T>=Extract<Union,{type: T}>;typeTest4=Test3<'c'>// success: Test4 === never// Then that should be substituted into FallbackWhenBottomtypeTest5=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

Related Issues:#29368, #29627,

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions