Skip to content

Commit

Permalink
Merge pull request #99 from andnp/UnionToIntersection
Browse files Browse the repository at this point in the history
Union to intersection
  • Loading branch information
andnp authored Apr 21, 2019
2 parents d0378b5 + 42cc8c3 commit 0d4b44d
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 14 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ npm install --save-dev simplytyped

**[Utils](#utils)**

[NoInfer](#noinfer) - [Nominal](#nominal) - [Nullable](#nullable) - [PromiseOr](#promiseor)
[NoInfer](#noinfer) - [Nominal](#nominal) - [Nullable](#nullable) - [PromiseOr](#promiseor) - [UnionToIntersection](#uniontointersection)

**[Functions](#functions)**

Expand Down Expand Up @@ -581,6 +581,30 @@ test('Will give back a promise containing given type union the type itself', t =

```

### UnionToIntersection
Defines an intersection type of all union items.
```ts
test('Union of Strings', t => {
type got = UnionToIntersection<'hi' | 'there'>;
type expected = 'hi' & 'there';

assert<got, expected>(t);
});

test('Union of Objects', t => {
type got = UnionToIntersection<{ a: 0 } | { b: 1 } | { c: 2 }>;

type expected = {
a: 0,
b: 1,
c: 2,
};

assert<got, expected>(t);
});

```

## Functions

### AnyFunc
Expand Down
17 changes: 4 additions & 13 deletions src/types/tuples.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {UnionToIntersection} from './utils';

export interface Vector<T> { readonly [x: number]: T; readonly length: number; }
export type Length<T extends Vector<any>> = T['length'];

Expand All @@ -9,18 +11,7 @@ export type Length<T extends Vector<any>> = T['length'];
export type UnionizeTuple<T extends Vector<any>> = T[number];
/**
* Gives an intersection of all values contained in a tuple.
* @param T a tuple of items up to 10
* @param T a tuple of items
* @returns an intersection of all items in the tuple
*/
export type IntersectTuple<T extends Vector<any>> =
Length<T> extends 1 ? T[0] :
Length<T> extends 2 ? T[0] & T[1] :
Length<T> extends 3 ? T[0] & T[1] & T[2] :
Length<T> extends 4 ? T[0] & T[1] & T[2] & T[3] :
Length<T> extends 5 ? T[0] & T[1] & T[2] & T[3] & T[4] :
Length<T> extends 6 ? T[0] & T[1] & T[2] & T[3] & T[4] & T[5] :
Length<T> extends 7 ? T[0] & T[1] & T[2] & T[3] & T[4] & T[5] & T[6] :
Length<T> extends 8 ? T[0] & T[1] & T[2] & T[3] & T[4] & T[5] & T[6] & T[7] :
Length<T> extends 9 ? T[0] & T[1] & T[2] & T[3] & T[4] & T[5] & T[6] & T[7] & T[8] :
Length<T> extends 10 ? T[0] & T[1] & T[2] & T[3] & T[4] & T[5] & T[6] & T[7] & T[8] & T[9] :
any;
export type IntersectTuple<T extends Vector<any>>= UnionToIntersection<T[number]>;
10 changes: 10 additions & 0 deletions src/types/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,13 @@ export type Nominal<T, N extends string> = T & Tagged<N>;
* @returns a the type union with a promise containing the given type
*/
export type PromiseOr<T> = Promise<T> | T;


/**
* Defines an intersection type of all union items.
* @param U Union of any types that will be intersected.
* @returns U items intersected
* @see https://stackoverflow.com/a/50375286/9259330
*/
export type UnionToIntersection<U> =
(U extends unknown ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
23 changes: 23 additions & 0 deletions test/utils/UnionToIntersection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import test from 'ava';
import { assert } from '../helpers/assert';

import { UnionToIntersection} from '../../src';

test('Union of Strings', t => {
type got = UnionToIntersection<'hi' | 'there'>;
type expected = 'hi' & 'there';

assert<got, expected>(t);
});

test('Union of Objects', t => {
type got = UnionToIntersection<{ a: 0 } | { b: 1 } | { c: 2 }>;

type expected = {
a: 0,
b: 1,
c: 2,
};

assert<got, expected>(t);
});

0 comments on commit 0d4b44d

Please sign in to comment.