Skip to content

Commit

Permalink
Add UnionToTuple type (#945)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
Emiyaaaaa and sindresorhus authored Aug 28, 2024
1 parent f120d8a commit 1f4f7a1
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export type {Spread} from './source/spread';
export type {IsInteger} from './source/is-integer';
export type {IsFloat} from './source/is-float';
export type {TupleToUnion} from './source/tuple-to-union';
export type {UnionToTuple} from './source/union-to-tuple';
export type {IntRange} from './source/int-range';
export type {IsEqual} from './source/is-equal';
export type {
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
- [`MultidimensionalReadonlyArray`](source/multidimensional-readonly-array.d.ts) - Create a type that represents a multidimensional readonly array of the given type and dimensions.
- [`ReadonlyTuple`](source/readonly-tuple.d.ts) - Create a type that represents a read-only tuple of the given type and length.
- [`TupleToUnion`](source/tuple-to-union.d.ts) - Convert a tuple/array into a union type of its elements.
- [`UnionToTuple`](source/union-to-tuple.d.ts) - Convert a union type into an unordered tuple type of its elements.

### Numeric

Expand Down
54 changes: 54 additions & 0 deletions source/union-to-tuple.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type {IsNever} from './is-never';
import type {UnionToIntersection} from './union-to-intersection';

/**
Returns the last element of a union type.
@example
```
type Last = LastOfUnion<1 | 2 | 3>;
//=> 3
```
*/
type LastOfUnion<T> =
UnionToIntersection<T extends any ? () => T : never> extends () => (infer R)
? R
: never;

/**
Convert a union type into an unordered tuple type of its elements.
This can be useful when you have objects with a finite set of keys and want a type defining only the allowed keys, but do not want to repeat yourself.
@example
```
import type {UnionToTuple} from 'type-fest';
type Numbers = 1 | 2 | 3;
type NumbersTuple = UnionToTuple<Numbers>;
//=> [1, 2, 3]
```
@example
```
import type {UnionToTuple} from 'type-fest';
const pets = {
dog: '🐶',
cat: '🐱',
snake: '🐍',
};
type Pet = keyof typeof pets;
//=> 'dog' | 'cat' | 'snake'
const petList = Object.keys(pets) as UnionToTuple<Pet>;
//=> ['dog', 'cat', 'snake']
```
@category Array
*/
export type UnionToTuple<T, L = LastOfUnion<T>> =
IsNever<T> extends false
? [...UnionToTuple<Exclude<T, L>>, L]
: [];
13 changes: 13 additions & 0 deletions test-d/union-to-tuple.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {expectAssignable, expectError, expectType} from 'tsd';
import type {UnionToTuple} from '../index';

type Options = UnionToTuple<'a' | 'b' | 'c'>;
// Results unordered
expectAssignable<['a', 'b', 'c'] | ['a', 'c', 'b'] | ['b', 'a', 'c'] | ['b', 'c', 'a'] | ['c', 'a', 'b'] | ['c', 'b', 'a']>({} as Options);
expectType<Options[number]>({} as ('a' | 'b' | 'c'));

type Options1 = UnionToTuple<1 | 2 | 3>;
expectType<Options1[number]>({} as (1 | 2 | 3));

type Options2 = UnionToTuple<boolean | 1>;
expectType<Options2[number]>({} as (1 | false | true));

0 comments on commit 1f4f7a1

Please sign in to comment.