Back to Type Challenges

README

questions/00869-extreme-distributeunions/README.md

latest2.2 KB
Original Source
<!--info-header-start--><h1>DistributeUnions </h1><blockquote><p>by Gabriel Vergnaud <a href="https://github.com/gvergnaud" target="_blank">@gvergnaud</a></p></blockquote><p><a href="https://tsch.js.org/869/play" target="_blank"></a> </p><!--info-header-end-->

Implement a type Distribute Unions, that turns a type of data structure containing union types into a union of all possible types of permitted data structures that don't contain any union. The data structure can be any combination of objects and tuples on any level of nesting.

For example:

ts
type T1 = DistributeUnions<[1 | 2, 'a' | 'b']>
// =>   [1, 'a'] | [2, 'a'] | [1, 'b'] | [2, 'b']

type T2 = DistributeUnions<{ type: 'a', value: number | string } | { type: 'b', value: boolean }>
//  =>  | { type 'a', value: number }
//      | { type 'a', value: string }
//      | { type 'b', value: boolean }

type T3 = DistributeUnions<[{ value: 'a' | 'b' },  { x: { y: 2 | 3  } }] | 17>
//  =>  | [{ value: 'a' },  { x: { y: 2  } }]
//      | [{ value: 'a' },  { x: { y: 3  } }]
//      | [{ value: 'b' },  { x: { y: 2  } }]
//      | [{ value: 'b' },  { x: { y: 3  } }]
//      | 17

For context, this type can be very useful if you want to exclude a case on deep data structures:

ts
type ExcludeDeep<A, B> = Exclude<DistributeUnions<A>, B>

type T0 = ExcludeDeep<[{ value: 'a' | 'b' },  { x: { y: 2 | 3  } }] | 17, [{ value: 'a' },  any]>
//  =>  | [{ value: 'b' },  { x: { y: 2  } }]
//      | [{ value: 'b' },  { x: { y: 3  } }]
//      | 17
<!--info-footer-start-->

<a href="../../README.md" target="_blank"></a> <a href="https://tsch.js.org/869/answer" target="_blank"></a> <a href="https://tsch.js.org/869/solutions" target="_blank"></a> <!--info-footer-end-->