# utility-types Collection of utility types, complementing TypeScript built-in mapped types and aliases (think "lodash" for static types). [![Latest Stable Version](https://img.shields.io/npm/v/utility-types.svg)](https://www.npmjs.com/package/utility-types) [![NPM Downloads](https://img.shields.io/npm/dm/utility-types.svg)](https://www.npmjs.com/package/utility-types) [![NPM Downloads](https://img.shields.io/npm/dt/utility-types.svg)](https://www.npmjs.com/package/utility-types) [![Bundlephobia Size](https://img.shields.io/bundlephobia/minzip/utility-types.svg)](https://www.npmjs.com/package/utility-types) [![Build Status](https://semaphoreci.com/api/v1/piotrekwitek/utility-types/branches/master/shields_badge.svg)](https://semaphoreci.com/piotrekwitek/utility-types) [![Dependency Status](https://img.shields.io/david/piotrwitek/utility-types.svg)](https://david-dm.org/piotrwitek/utility-types) [![License](https://img.shields.io/npm/l/utility-types.svg?style=flat)](https://david-dm.org/piotrwitek/utility-types?type=peer) [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/utility-types) _Found it useful? Want more updates?_ [**Show your support by giving a :star:**](https://github.com/piotrwitek/utility-types/stargazers) Buy Me a Coffee Become a Patron

### **What's new?** :tada: _Now updated to support **TypeScript v3.7**_ :tada:

## Features * Providing a set of [Common Types](#table-of-contents) for TypeScript projects that are idiomatic and complementary to existing [TypeScript Mapped Types](https://www.typescriptlang.org/docs/handbook/advanced-types.html) so you don't need to copy them between the projects. * Providing a set of [Additional Types](#) compatible with [Flow's Utility Types](https://flow.org/en/docs/types/utilities/) to allow much easier migration to `TypeScript`. ## Goals * Quality - thoroughly tested for type correctness with type-testing library `dts-jest` * Secure and minimal - no third-party dependencies * No runtime cost - it's type-level only ## Installation ```bash # NPM npm install utility-types # YARN yarn add utility-types ``` ## Compatibility Notes **TypeScript support** * `v3.x.x` - TypeScript v3.1+ * `v2.x.x` - TypeScript v2.8.1+ * `v1.x.x` - TypeScript v2.7.2+ ## Funding Issues **Utility-Types** is an open-source project created by people investing their time for the benefit of our community. Issues like bug fixes or feature requests can be very quickly resolved when funded through the IssueHunt platform. I highly recommend adding a bounty to the issue that you're waiting for to attract some contributors willing to work on it. [![Let's fund issues in this repository](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/76400842) ## Contributing We are open for contributions. If you're planning to contribute please make sure to read the contributing guide as it can save you from wasting your time: [CONTRIBUTING.md](/CONTRIBUTING.md) --- * _(built-in)_ - types built-in TypeScript, no need to import # Table of Contents ## Aliases & Type Guards * [`Primitive`](#primitive) * [`isPrimitive`](#isprimitive) * [`Falsy`](#falsy) * [`isFalsy`](#isfalsy) ## Union operators * [`SetIntersection`](#setintersectiona-b-same-as-extract) * [`SetDifference`](#setdifferencea-b-same-as-exclude) * [`SetComplement`](#setcomplementa-a1) * [`SymmetricDifference`](#symmetricdifferencea-b) * [`Exclude`](#excludea-b) _(built-in)_ * [`Extract`](#extracta-b) _(built-in)_ * [`NonNullable`](#nonnullablea) _(built-in)_ * [`NonUndefined`](#nonundefineda) ## Object operators * [`FunctionKeys`](#functionkeyst) * [`NonFunctionKeys`](#nonfunctionkeyst) * [`MutableKeys`](#mutablekeyst) * [`ReadonlyKeys`](#readonlykeyst) * [`RequiredKeys`](#requiredkeyst) * [`OptionalKeys`](#optionalkeyst) * [`Optional`](#optionalt-k) * [`Partial`](#partialt) _(built-in)_ * [`DeepPartial`](#deeppartialt) * [`Required`](#requiredt-k) * [`DeepRequired`](#deeprequiredt) * [`Readonly`](#readonlyt) _(built-in)_ * [`DeepReadonly`](#deepreadonlyt) * [`Mutable`](#mutablet) * [`Pick` _(built-in)_](#pickt-k-built-in) * [`Omit`](#omitt-k) _(built-in)_ * [`PickByValue`](#pickbyvaluet-valuetype) * [`PickByValueExact`](#pickbyvalueexactt-valuetype) * [`OmitByValue`](#omitbyvaluet-valuetype) * [`OmitByValueExact`](#omitbyvalueexactt-valuetype) * [`Intersection`](#intersectiont-u) * [`Diff`](#difft-u) * [`Subtract`](#subtractt-t1) * [`Overwrite`](#overwritet-u) * [`Assign`](#assignt-u) * [`ValuesType`](#valuestypet) ## Special operators * [`ReturnType`](#returntypet) _(built-in)_ * [`InstanceType`](#instancetypet) _(built-in)_ * [`PromiseType`](#promisetypet) * [`Unionize`](#unionizet) * [`Brand`](#brandt-u) * [`UnionToIntersection`](#uniontointersectionu) ## Flow's Utility Types * [`$Keys`](#keyst) * [`$Values`](#valuest) * [`$ReadOnly`](#readonly2) * [`$Diff`](#diff2) * [`$PropertyType`](#propertytypet-k) * [`$ElementType`](#elementtypet-k) * [`$Call`](#callt) * [`$Shape`](#shapet) * [`$NonMaybeType`](#nonmaybetypet) * [`Class`](#classt) * [`mixed`](#mixed) ## Deprecated API (use at own risk) * `getReturnOfExpression()` - from TS v2.0 it's better to use type-level `ReturnType` instead --- ### `Primitive` Type representing primitive types in JavaScript, and thus TypeScript: `string | number | bigint | boolean | symbol | null | undefined` You can test for singular of these types with [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) ### `isPrimitive` This is a [TypeScript Typeguard](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types) for the [`Primitive`](#primitive) type. This can be useful to control the type of a parameter as the program flows. Example: ```ts const consumer = (param: Primitive[] | Primitive): string => { if (isPrimitive(param)) { // typeof param === Primitive return String(param) + ' was Primitive'; } // typeof param === Primitive[] const resultArray = param .map(consumer) .map(rootString => '\n\t' + rootString); return resultArray.reduce((comm, newV) => comm + newV, 'this was nested:'); }; ``` [⇧ back to top](#table-of-contents) ### `Falsy` Type representing falsy values in TypeScript: `false | "" | 0 | null | undefined` > Except `NaN` which cannot be represented as a type literal ### `isFalsy` ```ts const consumer = (param: Falsy | string): string => { if (isFalsy(param)) { // typeof param === Falsy return String(param) + ' was Falsy'; } // typeof param === string return param.toString(); }; ``` [⇧ back to top](#table-of-contents) ### `SetIntersection` (same as Extract) Set intersection of given union types `A` and `B` **Usage:** ```ts import { SetIntersection } from 'utility-types'; // Expect: "2" | "3" type ResultSet = SetIntersection<'1' | '2' | '3', '2' | '3' | '4'>; // Expect: () => void type ResultSetMixed = SetIntersection void), Function>; ``` [⇧ back to top](#table-of-contents) ### `SetDifference` (same as Exclude) Set difference of given union types `A` and `B` **Usage:** ```ts import { SetDifference } from 'utility-types'; // Expect: "1" type ResultSet = SetDifference<'1' | '2' | '3', '2' | '3' | '4'>; // Expect: string | number type ResultSetMixed = SetDifference void), Function>; ``` [⇧ back to top](#table-of-contents) ### `SetComplement` Set complement of given union types `A` and (it's subset) `A1` **Usage:** ```ts import { SetComplement } from 'utility-types'; // Expect: "1" type ResultSet = SetComplement<'1' | '2' | '3', '2' | '3'>; ``` [⇧ back to top](#table-of-contents) ### `SymmetricDifference` Set difference of union and intersection of given union types `A` and `B` **Usage:** ```ts import { SymmetricDifference } from 'utility-types'; // Expect: "1" | "4" type ResultSet = SymmetricDifference<'1' | '2' | '3', '2' | '3' | '4'>; ``` [⇧ back to top](#table-of-contents) ### `NonNullable` Exclude `null` and `undefined` from set `A` [⇧ back to top](#table-of-contents) ### `NonUndefined` Exclude `undefined` from set `A` [⇧ back to top](#table-of-contents) ### `Exclude` Exclude subset `B` from set `A` [⇧ back to top](#table-of-contents) ### `Extract` Extract subset `B` from set `A` [⇧ back to top](#table-of-contents) ## Operations on objects ### `FunctionKeys` Get union type of keys that are functions in object type `T` **Usage:** ```ts import { FunctionKeys } from 'utility-types'; type MixedProps = { name: string; setName: (name: string) => void }; // Expect: "setName" type Keys = FunctionKeys; ``` [⇧ back to top](#table-of-contents) ### `NonFunctionKeys` Get union type of keys that are non-functions in object type `T` **Usage:** ```ts import { NonFunctionKeys } from 'utility-types'; type MixedProps = { name: string; setName: (name: string) => void }; // Expect: "name" type Keys = NonFunctionKeys; ``` [⇧ back to top](#table-of-contents) ### `MutableKeys` Get union type of keys that are mutable (not readonly) in object type `T` Alias: `WritableKeys` **Usage:** ```ts import { MutableKeys } from 'utility-types'; type Props = { readonly foo: string; bar: number }; // Expect: "bar" type Keys = MutableKeys; ``` [⇧ back to top](#table-of-contents) ### `ReadonlyKeys` Get union type of keys that are readonly in object type `T` **Usage:** ```ts import { ReadonlyKeys } from 'utility-types'; type Props = { readonly foo: string; bar: number }; // Expect: "foo" type Keys = ReadonlyKeys; ``` [⇧ back to top](#table-of-contents) ### `RequiredKeys` Get union type of keys that are required in object type `T` **Usage:** ```ts import { RequiredKeys } from 'utility-types'; type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; }; // Expect: "req" | "reqUndef" type Keys = RequiredKeys; ``` [⇧ back to top](#table-of-contents) ### `OptionalKeys` Get union type of keys that are optional in object type `T` **Usage:** ```ts import { OptionalKeys } from 'utility-types'; type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; }; // Expect: "opt" | "optUndef" type Keys = OptionalKeys; ``` [⇧ back to top](#table-of-contents) ### `Optional` From `T` make a set of properties by key `K` become optional **Usage:** ```ts import { Optional } from 'utility-types'; type Props = { name: string; age: number; visible: boolean; }; // Expect: { name?: string; age?: number; visible?: boolean; } type Props = Optional // Expect: { name: string; age?: number; visible?: boolean; } type Props = Optional; ``` [⇧ back to top](#table-of-contents) ### `Pick` _(built-in)_ From `T` pick a set of properties by key `K` **Usage:** ```ts type Props = { name: string; age: number; visible: boolean }; // Expect: { age: number; } type Props = Pick; ``` [⇧ back to top](#table-of-contents) ### `PickByValue` From `T` pick a set of properties by value matching `ValueType`. _(Credit: [Piotr Lewandowski](https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c))_ **Usage:** ```ts import { PickByValue } from 'utility-types'; type Props = { req: number; reqUndef: number | undefined; opt?: string; }; // Expect: { req: number } type Props = PickByValue; // Expect: { req: number; reqUndef: number | undefined; } type Props = PickByValue; ``` [⇧ back to top](#table-of-contents) ### `PickByValueExact` From `T` pick a set of properties by value matching exact `ValueType`. **Usage:** ```ts import { PickByValueExact } from 'utility-types'; type Props = { req: number; reqUndef: number | undefined; opt?: string; }; // Expect: { req: number } type Props = PickByValueExact; // Expect: { reqUndef: number | undefined; } type Props = PickByValueExact; ``` [⇧ back to top](#table-of-contents) ### `Omit` From `T` remove a set of properties by key `K` **Usage:** ```ts import { Omit } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: { name: string; visible: boolean; } type Props = Omit; ``` [⇧ back to top](#table-of-contents) ### `OmitByValue` From `T` remove a set of properties by value matching `ValueType`. _(Credit: [Piotr Lewandowski](https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c))_ **Usage:** ```ts import { OmitByValue } from 'utility-types'; type Props = { req: number; reqUndef: number | undefined; opt?: string; }; // Expect: { reqUndef: number | undefined; opt?: string; } type Props = OmitByValue; // Expect: { opt?: string; } type Props = OmitByValue; ``` [⇧ back to top](#table-of-contents) ### `OmitByValueExact` From `T` remove a set of properties by value matching exact `ValueType`. **Usage:** ```ts import { OmitByValueExact } from 'utility-types'; type Props = { req: number; reqUndef: number | undefined; opt?: string; }; // Expect: { reqUndef: number | undefined; opt?: string; } type Props = OmitByValueExact; // Expect: { req: number; opt?: string } type Props = OmitByValueExact; ``` [⇧ back to top](#table-of-contents) ### `Intersection` From `T` pick properties that exist in `U` **Usage:** ```ts import { Intersection } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; type DefaultProps = { age: number }; // Expect: { age: number; } type DuplicatedProps = Intersection; ``` [⇧ back to top](#table-of-contents) ### `Diff` From `T` remove properties that exist in `U` **Usage:** ```ts import { Diff } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; type DefaultProps = { age: number }; // Expect: { name: string; visible: boolean; } type RequiredProps = Diff; ``` [⇧ back to top](#table-of-contents) ### `Subtract` From `T` remove properties that exist in `T1` (`T1` has a subset of the properties of `T`) **Usage:** ```ts import { Subtract } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; type DefaultProps = { age: number }; // Expect: { name: string; visible: boolean; } type RequiredProps = Subtract; ``` [⇧ back to top](#table-of-contents) ### `Overwrite` From `U` overwrite properties to `T` **Usage:** ```ts import { Overwrite } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; type NewProps = { age: string; other: string }; // Expect: { name: string; age: string; visible: boolean; } type ReplacedProps = Overwrite; ``` [⇧ back to top](#table-of-contents) ### `Assign` From `U` assign properties to `T` (just like object assign) **Usage:** ```ts import { Assign } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; type NewProps = { age: string; other: string }; // Expect: { name: string; age: number; visible: boolean; other: string; } type ExtendedProps = Assign; ``` [⇧ back to top](#table-of-contents) ### `ValuesType` Get the union type of all the values in an object, tuple, array or array-like type `T`. **Usage:** ```ts import { ValuesType } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: string | number | boolean type PropsValues = ValuesType; type NumberArray = number[]; // Expect: number type NumberItems = ValuesType; type ReadonlyNumberTuple = readonly [1, 2]; // Expect: 1 | 2 type AnotherNumberUnion = ValuesType; type BinaryArray = Uint8Array; // Expect: number type BinaryItems = ValuesType; ``` [⇧ back to top](#table-of-contents) ### `Partial` Make all properties of object type optional [⇧ back to top](#table-of-contents) ### `Required` From `T` make a set of properties by key `K` become required **Usage:** ```ts import { Required } from 'utility-types'; type Props = { name?: string; age?: number; visible?: boolean; }; // Expect: { name: string; age: number; visible: boolean; } type Props = Required // Expect: { name?: string; age: number; visible: boolean; } type Props = Required; ``` [⇧ back to top](#table-of-contents) ### `Readonly` Make all properties of object type readonly [⇧ back to top](#table-of-contents) ### `Mutable` From `T` make all properties become mutable Alias: `Writable` ```ts import { Mutable } from 'utility-types'; type Props = { readonly name: string; readonly age: number; readonly visible: boolean; }; // Expect: { name: string; age: number; visible: boolean; } Mutable; ``` [⇧ back to top](#table-of-contents) ### `ReturnType` Obtain the return type of a function [⇧ back to top](#table-of-contents) ### `InstanceType` Obtain the instance type of a class [⇧ back to top](#table-of-contents) ### `Unionize` Disjoin object to form union of objects, each with single property **Usage:** ```ts import { Unionize } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: { name: string; } | { age: number; } | { visible: boolean; } type UnionizedType = Unionize; ``` [⇧ back to top](#table-of-contents) ### `PromiseType` Obtain Promise resolve type **Usage:** ```ts import { PromiseType } from 'utility-types'; // Expect: string type Response = PromiseType>; ``` [⇧ back to top](#table-of-contents) ### `DeepReadonly` Readonly that works for deeply nested structures **Usage:** ```ts import { DeepReadonly } from 'utility-types'; type NestedProps = { first: { second: { name: string; }; }; }; // Expect: { // readonly first: { // readonly second: { // readonly name: string; // }; // }; // } type ReadonlyNestedProps = DeepReadonly; ``` [⇧ back to top](#table-of-contents) ### `DeepRequired` Required that works for deeply nested structures **Usage:** ```ts import { DeepRequired } from 'utility-types'; type NestedProps = { first?: { second?: { name?: string; }; }; }; // Expect: { // first: { // second: { // name: string; // }; // }; // } type RequiredNestedProps = DeepRequired; ``` [⇧ back to top](#table-of-contents) ### `DeepNonNullable` NonNullable that works for deeply nested structure **Usage:** ```ts import { DeepNonNullable } from 'utility-types'; type NestedProps = { first?: null | { second?: null | { name?: string | null | undefined; }; }; }; // Expect: { // first: { // second: { // name: string; // }; // }; // } type RequiredNestedProps = DeepNonNullable; ``` [⇧ back to top](#table-of-contents) ### `DeepPartial` Partial that works for deeply nested structures **Usage:** ```ts import { DeepPartial } from 'utility-types'; type NestedProps = { first: { second: { name: string; }; }; }; // Expect: { // first?: { // second?: { // name?: string; // }; // }; // } type PartialNestedProps = DeepPartial; ``` [⇧ back to top](#table-of-contents) ### `Brand` Define nominal type of `U` based on type of `T`. Similar to Opaque types in Flow. **Usage:** ```ts import { Brand } from 'utility-types'; type USD = Brand type EUR = Brand const tax = 5 as USD; const usd = 10 as USD; const eur = 10 as EUR; function gross(net: USD): USD { return (net + tax) as USD; } gross(usd); // ok gross(eur); // Type '"EUR"' is not assignable to type '"USD"'. ``` [⇧ back to top](#table-of-contents) ### `UnionToIntersection` Get intersection type given union type `U` **Usage:** ```ts import { UnionToIntersection } from 'utility-types'; // Expect: { name: string } & { age: number } & { visible: boolean } UnionToIntersection<{ name: string } | { age: number } | { visible: boolean }> ``` [⇧ back to top](#table-of-contents) --- ## Flow's Utility Types ### `$Keys` get the union type of all the keys in an object type `T`
https://flow.org/en/docs/types/utilities/#toc-keys **Usage:** ```ts import { $Keys } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: "name" | "age" | "visible" type PropsKeys = $Keys; ``` [⇧ back to top](#flows-utility-types) ### `$Values` get the union type of all the values in an object type `T`
https://flow.org/en/docs/types/utilities/#toc-values **Usage:** ```ts import { $Values } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: string | number | boolean type PropsValues = $Values; ``` [⇧ back to top](#flows-utility-types) ###
`$ReadOnly` get the read-only version of a given object type `T`
https://flow.org/en/docs/types/utilities/#toc-readonly **Usage:** ```ts import { $ReadOnly } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: Readonly<{ name: string; age?: number | undefined; visible: boolean; }> type ReadOnlyProps = $ReadOnly; ``` [⇧ back to top](#flows-utility-types) ### `$Diff` get the set difference of a given object types `T` and `U` (`T \ U`)
https://flow.org/en/docs/types/utilities/#toc-diff **Usage:** ```ts import { $Diff } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; type DefaultProps = { age: number }; // Expect: { name: string; visible: boolean; } type RequiredProps = $Diff; ``` [⇧ back to top](#flows-utility-types) ### `$PropertyType` get the type of property of an object at a given key `K`
https://flow.org/en/docs/types/utilities/#toc-propertytype **Usage:** ```ts import { $PropertyType } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: string type NameType = $PropertyType; type Tuple = [boolean, number]; // Expect: boolean type A = $PropertyType; // Expect: number type B = $PropertyType; ``` [⇧ back to top](#flows-utility-types) ### `$ElementType` get the type of elements inside of array, tuple or object of type `T`, that matches the given index type `K`
https://flow.org/en/docs/types/utilities/#toc-elementtype **Usage:** ```ts import { $ElementType } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: string type NameType = $ElementType; type Tuple = [boolean, number]; // Expect: boolean type A = $ElementType; // Expect: number type B = $ElementType; type Arr = boolean[]; // Expect: boolean type ItemsType = $ElementType; type Obj = { [key: string]: number }; // Expect: number type ValuesType = $ElementType; ``` [⇧ back to top](#flows-utility-types) ### `$Call` get the return type of a given expression type
https://flow.org/en/docs/types/utilities/#toc-call **Usage:** ```ts import { $Call } from 'utility-types'; // Common use-case const add = (amount: number) => ({ type: 'ADD' as 'ADD', payload: amount }); type AddAction = $Call; // { type: 'ADD'; payload: number } // Examples migrated from Flow docs type ExtractPropType = (arg: T) => T['prop']; type Obj = { prop: number }; type PropType = $Call>; // number // type Nope = $Call>; // Error: argument doesn't match `Obj`. type ExtractReturnType any> = (arg: T) => ReturnType; type Fn = () => number; type FnReturnType = $Call>; // number ``` [⇧ back to top](#flows-utility-types) ### `$Shape` Copies the shape of the type supplied, but marks every field optional.
https://flow.org/en/docs/types/utilities/#toc-shape **Usage:** ```ts import { $Shape } from 'utility-types'; type Props = { name: string; age: number; visible: boolean }; // Expect: Partial type PartialProps = $Shape; ``` [⇧ back to top](#flows-utility-types) ### `$NonMaybeType` Converts a type `T` to a non-maybe type. In other words, the values of `$NonMaybeType` are the values of `T` except for `null` and `undefined`.
https://flow.org/en/docs/types/utilities/#toc-nonmaybe **Usage:** ```ts import { $NonMaybeType } from 'utility-types'; type MaybeName = string | null; // Expect: string type Name = $NonMaybeType; ``` [⇧ back to top](#flows-utility-types) ### `Class` Given a type T representing instances of a class C, the type Class is the type of the class C
https://flow.org/en/docs/types/utilities/#toc-class \* Differs from original Flow's util - implements only constructor part and won't include any static members. Additionally classes in Typescript are not treated as nominal **Usage:** ```ts import { Class } from 'utility-types'; function makeStore(storeClass: Class): Store { return new storeClass(); } ``` [⇧ back to top](#flows-utility-types) ### mixed An arbitrary type that could be anything (same as `unknown`)
https://flow.org/en/docs/types/mixed [⇧ back to top](#table-of-contents) --- ## Related Projects - [`ts-toolbelt`](https://github.com/pirix-gh/ts-toolbelt) - Higher type safety for TypeScript - [`$mol_type`](https://github.com/eigenmethod/mol/tree/master/type) - Collection of TypeScript meta types for complex logic --- ## License [MIT License](/LICENSE) Copyright (c) 2016 Piotr Witek (http://piotrwitek.github.io)