UNPKG

@cowprotocol/cow-sdk

Version:

<p align="center"> <img width="400" src="https://github.com/cowprotocol/cow-sdk/raw/main/docs/images/CoW.png" /> </p>

878 lines (694 loc) β€’ 32.2 kB
<p align="center"> <img src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/240/google/146/toolbox_1f9f0.png" width="120" alt="ts-essentials"> <h3 align="center">ts-essentials</h3> <p align="center">All essential TypeScript types in one place πŸ€™</p> <p align="center"> <img alt="Downloads" src="https://img.shields.io/npm/dm/ts-essentials.svg"> <img alt="Build status" src="https://github.com/krzkaczor/ts-essentials/actions/workflows/ci.yml/badge.svg"> <a href="/package.json"><img alt="Software License" src="https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square"></a> <img src="https://img.shields.io/badge/all_contributors-29-orange.svg?style=flat-square" alt="All Contributors"> <a href="https://codechecks.io"><img src="https://raw.githubusercontent.com/codechecks/docs/master/images/badges/badge-default.svg?sanitize=true" alt="codechecks.io"></a> </p> </p> ## Install ```sh npm install --save-dev ts-essentials ``` πŸ‘‰ We require `typescript>=3.7`. If you're looking for support for older TS versions use `ts-essentials@3` (for 3.6>=) or `ts-essentials@2` instead. If you use any [functions](https://github.com/krzkaczor/ts-essentials/blob/master/lib/functions.ts) you should add `ts-essentials` to your `dependencies` (`npm install --save ts-essentials`) to avoid runtime errors in production. ## What's inside? - [Install](#Install) - [What's inside?](#Whats-inside) - [Basic](#Basic) - [Dictionaries](#Dictionaries) - [Deep\* wrapper types](#Deep-wrapper-types) - DeepPartial - DeepRequired - DeepReadonly - DeepNonNullable - DeepNullable - DeepUndefinable - [Writable & DeepWritable](#Writable) - [Buildable](#Buildable) - [Omit](#Omit) - [StrictOmit](#StrictOmit) - [Comparison between `Omit` and `StrictOmit`](#Comparison-between-Omit-and-StrictOmit) - [DeepOmit](#DeepOmit) - [OmitProperties](#OmitProperties) - [PickProperties](#PickProperties) - [NonNever](#NonNever) - [Merge](#Merge) - [MarkRequired](#MarkRequired) - [MarkOptional](#MarkOptional) - [ReadonlyKeys](#ReadonlyKeys) - [WritableKeys](#WritableKeys) - [OptionalKeys](#OptionalKeys) - [RequiredKeys](#RequiredKeys) - [PickKeys](#pickkeys) - [UnionToIntersection](#UnionToIntersection) - [Opaque types](#Opaque-types) - [Tuple constraint](#Tuple-constraint) - [Exhaustive switch cases](#Exhaustive-switch-cases) - [ValueOf type](#ValueOf-type) - [ElementOf type](#ElementOf-type) - [AsyncOrSync type](#AsyncOrSync-type) - [Awaited type](#awaited-type) - [Newable](#newable) - [Assertions](#Assertions) - [Exact](#Exact) - [XOR](#XOR) - [Functional type essentials](#functional-type-essentials) - Head - Tail - [Contributors](#Contributors) ### Basic - `Primitive` type matching all primitive values. - `noop` function that takes any arguments and returns nothing, as a placeholder for e.g. callbacks. ### Dictionaries _keywords: map_ ```typescript const stringDict: Dictionary<string> = { a: "A", b: "B", }; // Specify second type argument to change dictionary keys type const dictOfNumbers: Dictionary<string, number> = { 420: "four twenty", 1337: "HAX", }; // You may specify union types as key to cover all possible cases. It acts the same as Record from TS's standard library export type DummyOptions = "open" | "closed" | "unknown"; const dictFromUnionType: Dictionary<number, DummyOptions> = { closed: 1, open: 2, unknown: 3, }; // and get dictionary values type stringDictValues = DictionaryValues<typeof stringDict>; // Result: string // When building a map using JS objects consider using SafeDictionary const safeDict: SafeDictionary<number> = {}; const value: number | undefined = safeDict["foo"]; // With SafeDictionary you don't need to use all of the sub-types of a finite type. // If you care about the key exhaustiveness, use a regular Dictionary. type ConfigKeys = "LOGLEVEL" | "PORT" | "DEBUG"; const configSafeDict: SafeDictionary<number, ConfigKeys> = { LOGLEVEL: 2, }; const maybePort: number | undefined = configSafeDict["PORT"]; const configDict: Dictionary<number, ConfigKeys> = { LOGLEVEL: 2, PORT: 8080, DEBUG: 1, }; const port: number = configDict["PORT"]; ``` ### Deep\* wrapper types - DeepPartial - DeepRequired - DeepReadonly - DeepNonNullable - DeepNullable - DeepUndefinable _keywords: recursive, nested, optional_ ```typescript type ComplexObject = { simple: number; nested: { a: string; array: [{ bar: number }]; }; }; type ComplexObjectPartial = DeepPartial<ComplexObject>; const samplePartial: ComplexObjectPartial = { nested: { array: [{}], }, }; type ComplexObjectAgain = DeepRequired<ComplexObjectPartial>; const sampleRequired: ComplexObjectAgain = { simple: 5, nested: { a: "test", array: [{ bar: 1 }], }, }; type ComplexObjectReadonly = DeepReadonly<ComplexObject>; type ComplexNullableObject = { simple: number | null | undefined; nested: { a: string | null | undefined; array: [{ bar: number | null | undefined }] | null | undefined; }; }; type ComplexObjectNonNullable = DeepNonNullable<ComplexNullableObject>; const sampleNonNullable: ComplexObjectNonNullable = { simple: 5, nested: { a: "test", array: [{ bar: null }], // Error: Type 'null' is not assignable to type 'number' }, }; type ComplexObjectNullable = DeepNullable<ComplexObject>; const sampleDeepNullable1: ComplexObjectNullable = { simple: null, nested: { a: null, array: [{ bar: null }], }, }; const sampleDeepNullable2: ComplexObjectNullable = { simple: 1, nested: { array: [null], // OK // error -- property `a` missing, should be `number | null` }, }; // DeepUndefinable will come in handy if: // - you want to explicitly assign values to all of the properties // AND // - the expression used for the assignment can return an `undefined` value // In most situations DeepPartial will suffice. declare function tryGet(name: string): string | undefined; type ComplexObjectUndefinable = DeepUndefinable<ComplexObject>; const sampleDeepUndefinable1: ComplexObjectUndefinable = { simple: undefined, nested: { a: tryGet("a-value"), array: [{ bar: tryGet("bar-value") }], }, }; const sampleDeepUndefinable2: ComplexObjectUndefinable = { // error -- property `simple` missing, should be `number | undefined` nested: { array: [[{ bar: undefined }]], // error -- property `a` missing, should be `string | undefined` }, }; ``` ### Writable Make all attributes of object writable. ```typescript type Foo = { readonly a: number; readonly b: string; }; const foo: Foo = { a: 1, b: "b" }; (foo as Writable<typeof foo>).a = 42; ``` ```typescript type Foo = { readonly foo: string; bar: { readonly x: number; }; }[]; const test: DeepWritable<Foo> = [ { foo: "a", bar: { x: 5, }, }, ]; // we can freely write to this object test[0].foo = "b"; test[0].bar.x = 2; ``` ### Buildable _keywords: builder_ A combination of both `DeepWritable` and `DeepPartial`. This type allows building an object step-by-step by assigning values to its attributes in multiple statements. ```typescript interface ReadonlyObject extends Readonly<{ simple: number; nested: Readonly<{ a: string; array: ReadonlyArray<Readonly<{ bar: number }>>; }>; }> {} const buildable: Buildable<ReadonlyObject> = {}; buildable.simple = 7; buildable.nested = {}; buildable.nested.a = "test"; buildable.nested.array = []; buildable.nested.array.push({ bar: 1 }); const finished = buildable as ReadonlyObject; ``` ### Omit Our version of `Omit` is renamed to `StrictOmit` in `v3`, since the builtin `Omit` has become part of TypeScript 3.5 ### StrictOmit Usage is similar to the builtin version, but checks the filter type more strictly. ```typescript type ComplexObject = { simple: number; nested: { a: string; array: [{ bar: number }]; }; }; type SimplifiedComplexObject = StrictOmit<ComplexObject, "nested">; // Result: // { // simple: number // } // if you want to Omit multiple properties just use union type: type SimplifiedComplexObject = StrictOmit<ComplexObject, "nested" | "simple">; // Result: // { } (empty type) ``` #### Comparison between `Omit` and `StrictOmit` Following the code above, we can compare the behavior of `Omit` and `StrictOmit`. ```typescript type SimplifiedComplexObjectWithStrictOmit = StrictOmit<ComplexObject, "nested" | "simple" | "nonexistent">; // Result: error // Type '"simple" | "nested" | "nonexistent"' does not satisfy the constraint '"simple" | "nested"'. // Type '"nonexistent"' is not assignable to type '"simple" | "nested"'. type SimplifiedComplexObjectWithOmit = Omit<ComplexObject, "nested" | "simple" | "nonexistent">; // Result: no error ``` As is shown in the example, `StrictOmit` ensures that no extra key is specified in the filter. ### DeepOmit Recursively omit deep properties according to key names. Here is the `Teacher` interface. ```typescript interface Teacher { name: string; gender: string; students: { name: string; score: number }[]; } ``` Now suppose you want to omit `gender` property of `Teacher`, and `score` property of `students`. You can achieve this with a simple type filter. In the filter, the properties to be omitted completely should be defined as `never`. For the properties you want to partially omit, you should recursively define the sub-properties to be omitted. ```typescript type TeacherSimple = DeepOmit< Teacher, { gender: never; students: { score: never; }; } >; // The result will be: // { // name: string, // students: {name: string}[] // } ``` NOTE - `DeepOmit` works fine with `Array`s and `Set`s. When applied to a `Map`, the filter is only applied to its value. - If there exists any property in the filter which is not in the original type, an error will occur. ### OmitProperties _keywords: filter, props_ Removes all properties extending type `P` in type `T`. NOTE: it works opposite to filtering. ```typescript interface Example { log(): void; version: string; } type ExampleWithoutMethods = OmitProperties<Example, Function>; // Result: // { // version: string; // } // if you want to Omit multiple properties just use union type like type ExampleWithoutMethods = OmitProperties<Example, Function | string>; // Result: // { } (empty type) ``` ### PickProperties Pick only properties extending type `P` in type `T`. ```typescript interface Example { log(): void; version: string; versionNumber: number; } type ExampleOnlyMethods = PickProperties<Example, Function>; // Result: // { // log(): void; // } // if you want to pick multiple properties just use union type like type ExampleOnlyMethodsAndString = PickProperties<Example, Function | string>; // Result: // { // log(): void; // version: string; // } ``` ### NonNever Useful for purifying object types. It improves intellisense but also allows for extracting keys satisfying a conditional type. ```typescript type GetDefined<TypesMap extends { [key: string]: any }> = keyof NonNever< { [T in keyof TypesMap]: TypesMap[T] extends undefined ? never : TypesMap[T] } >; ``` ### NonEmptyObject Useful for accepting only objects with keys, great after a filter like OmitProperties or PickProperties. ```typescript /* return never if the object doesn't have any number value*/ type NumberDictionary<T> = NonEmptyObject<PickProperties<T, number>>; // return { a: number } type SomeObject = NumberDictionary<{ a: number; b: string }>; // return never type EmptyObject = NumberDictionary<{}>; ``` ### Merge _keywords: override_ ```typescript type Foo = { a: number; b: string; }; type Bar = { b: number; }; const xyz: Merge<Foo, Bar> = { a: 4, b: 2 }; // Result: // { // a: number, // b: number, // } ``` ### MarkRequired Useful when you're sure some optional properties will be set. A real life example: when selecting an object with its related entities from an ORM. ```typescript class User { id: number; posts?: Post[]; photos?: Photo[]; } type UserWithPosts = MarkRequired<User, "posts">; // example usage with a TypeORM repository -- `posts` are now required, `photos` are still optional async function getUserWithPosts(id: number): Promise<UserWithPosts> { return userRepo.findOneOrFail({ id }, { relations: ["posts"] }) as Promise<UserWithPosts>; } ``` ### MarkOptional Useful when you want to make some properties optional without creating a separate type. ```typescript interface User { id: number; name: string; email: string; password: string; } type UserWithoutPassword = MarkOptional<User, "password">; // Result: // { // id: number; // name: string; // email: string; // password?: string; // } ``` ### ReadonlyKeys Gets keys of an object which are readonly. ```typescript type T = { readonly a: number; b: string; }; type Result = ReadonlyKeys<T>; // Result: // "a" ``` ### WritableKeys Gets keys of an object which are writable. ```typescript type T = { readonly a: number; b: string; }; type Result = WritableKeys<T>; // Result: // "b" ``` ### OptionalKeys Gets keys of an object which are optional. ```typescript type T = { a: number; b?: string; c: string | undefined; d?: string; }; type Result = OptionalKeys<T>; // Result: // "b" | "d" ``` ### RequiredKeys Gets keys of an object which are required. ```typescript type T = { a: number; b?: string; c: string | undefined; d?: string; }; type Result = RequiredKeys<T>; // Result: // "a" | "c" ``` ### PickKeys Gets keys of properties of given type in object type. ```typescript type T = { a: number; b?: string; c: string | undefined; d: string; }; type Result1 = PickKeys<T, string>; // Result1: // "d" type Result2 = PickKeys<T, string | undefined>; // Result2: // "b" | "c" | "d" ``` ### UnionToIntersection Useful for converting mapped types with function values to intersection type (so in this case - overloaded function). ```typescript type Foo = { bar: string; xyz: number; }; type Fn = UnionToIntersection<{ [K in keyof Foo]: (type: K, arg: Foo[K]) => any }[keyof Foo]>; ``` ### Opaque types Opaque types allow you to create unique type that can't be assigned to base type by accident. Good examples of opaque types include: - JWTs or other tokens - these are special kinds of string used for authorization purposes. If your app uses multiple types of tokens each should be a separate opaque type to avoid confusion. - specific currencies - amount of different currencies shouldn't be mixed - bitcoin address - special kind of string It's **critical** to understand that each token (second argument to `Opaque`) has to be unique across your codebase. We encourage you to leverage a pattern where you have single function to validate base type and create opaque type. ```typescript type PositiveNumber = Opaque<number, "PositiveNumber">; function makePositiveNumber(n: number): PositiveNumber { if (n <= 0) { throw new Error(`Value ${n} is not positive !`); } return (n as any) as PositiveNumber; // this ugly cast is required but only when "producing" opaque types } type NegativeNumber = Opaque<number, "NegativeNumber">; function makeNegativeNumber(n: number): NegativeNumber { if (n >= 0) { throw new Error(`Value ${n} is not negative !`); } return (n as any) as NegativeNumber; // this ugly cast is required but only when "producing" opaque types } let a = makePositiveNumber(5); // runtime check let b = makeNegativeNumber(-10); // runtime check a = b; // error at compile time ``` ### Tuple constraint ```typescript function foo<T extends Tuple>(tuple: T): T { return tuple; } const ret = foo(["s", 1]); // return type of [string, number] ``` You can also parametrize `Tuple` type with a type argument to constraint it to certain types, i.e. `Tuple<string | number>`. ### Exhaustive switch cases ```typescript function actOnDummyOptions(options: DummyOptions): string { switch (options) { case "open": return "it's open!"; case "closed": return "it's closed"; case "unknown": return "i have no idea"; default: // if you would add another option to DummyOptions, you'll get error here! throw new UnreachableCaseError(options); } } ``` ### ValueOf type ```typescript const obj = { id: "123e4567-e89b-12d3-a456-426655440000", name: "Test object", timestamp: 1548768231486, }; type objKeys = ValueOf<typeof obj>; // Result: string | number ``` ### ElementOf type ```typescript const array = [1, 2, true, false]; type arrayElement = ElementOf<typeof array>; // Result: number | boolean ``` ### AsyncOrSync type Useful as a return type in interfaces or abstract classes with missing implementation ```typescript interface CiProvider { getSHA(): AsyncOrSync<string>; // same as getSHA(): Promise<string> | string; } class Circle implements CiProvider { // implementation can use sync version getSHA() { return "abc"; } } class Travis implements CiProvider { // implementation can use async version when needed async getSHA() { // do async call return "def"; } } // to get original type use AsyncOrSyncType AsyncOrSyncType<AsyncOrSync<number>> // return 'number' ``` ### Awaited type Unwrap promised type: ```typescript Awaited<Promise<number>> // number ``` ### Newable _keywords: constructor, class_ Type useful when working with classes (not their instances). ```typescript class TestCls { constructor(arg1: string) {} } const t1: Newable<any> = TestCls; ``` ### Assertions _keywords: invariant_ Simple runtime assertion that narrows involved types using [assertion functions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions). Note: This function is not purely type level and leaves minimal runtime trace in generated code. ```typescript const something: string | undefined = "abc" as any; assert(something, "Something has to be defined!"); // from now on `something` is string, if this wouldn't be a case, assert would throw const anything = "abc" as any; assert(anything instanceof String, "anything has to be a string!"); // from now on `anything` is string ``` ### Exact _keywords: same, equals, equality_ `Exact<TYPE, SHAPE>` Checks if `TYPE` is exactly the same as `SHAPE`, if yes than `TYPE` is returned otherwise `never`. ```typescript type ABC = { a: number; b: number; c: number } type BC = { b: number; c: number } type C = { c: number } Exact<ABC, C> // returns NEVER Exact<C, C> // returns C ``` ### XOR Gets the XOR (Exclusive-OR) type which could make 2 types exclude each other. ```typescript type A = { a: string }; type B = { a: number; b: boolean }; type C = { c: number }; let A_XOR_B: XOR<A, B>; let A_XOR_C: XOR<A, C>; // fail A_XOR_B = { a: 0 }; A_XOR_B = { b: true }; A_XOR_B = { a: "", b: true }; A_XOR_C = { a: "", c: 0 }; // would be allowed with `A | C` type // ok A_XOR_B = { a: 0, b: true }; A_XOR_B = { a: "" }; A_XOR_C = { c: 0 }; ``` ### Functional type essentials `Head` & `Tail`: useful for functional programming, or as building blocks for more complex functional types. ```typescript function tail<T extends any[]>(array: T): Tail<T> { return array.slice(1) as Tail<T>; } type FirstParameter<FnT extends (...args: any) => any> = FnT extends (...args: infer ArgsT) => any ? Head<ArgsT> : never; ``` ## Contributors Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tr> <td align="center"><a href="https://twitter.com/krzkaczor"><img src="https://avatars2.githubusercontent.com/u/1814312?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=krzkaczor" title="Code">πŸ’»</a> <a href="#business-krzkaczor" title="Business development">πŸ’Ό</a> <a href="#example-krzkaczor" title="Examples">πŸ’‘</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=krzkaczor" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://scholar.google.com/citations?user=3xZtvpAAAAAJ"><img src="https://avatars3.githubusercontent.com/u/9780746?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xiao Liang</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=yxliang01" title="Code">πŸ’»</a> <a href="#ideas-yxliang01" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=yxliang01" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/Andarist"><img src="https://avatars2.githubusercontent.com/u/9800850?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mateusz BurzyΕ„ski</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=Andarist" title="Code">πŸ’»</a> <a href="#ideas-Andarist" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=Andarist" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/macbem"><img src="https://avatars1.githubusercontent.com/u/12464061?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Maciej Bembenista</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=macbem" title="Code">πŸ’»</a> <a href="#ideas-macbem" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=macbem" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/MichaelTontchev"><img src="https://avatars0.githubusercontent.com/u/12261336?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Tontchev</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=MichaelTontchev" title="Code">πŸ’»</a> <a href="#ideas-MichaelTontchev" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=MichaelTontchev" title="Documentation">πŸ“–</a></td> <td align="center"><a href="http://ThomasdH.blogspot.com"><img src="https://avatars0.githubusercontent.com/u/3889750?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Thomas den Hollander</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=ThomasdenH" title="Code">πŸ’»</a> <a href="#ideas-ThomasdenH" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=ThomasdenH" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://twitter.com/esamatti"><img src="https://avatars3.githubusercontent.com/u/225712?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Esa-Matti Suuronen</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=epeli" title="Code">πŸ’»</a> <a href="#ideas-epeli" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=epeli" title="Documentation">πŸ“–</a></td> </tr> <tr> <td align="center"><a href="https://github.com/IlyaSemenov"><img src="https://avatars1.githubusercontent.com/u/128121?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ilya Semenov</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=IlyaSemenov" title="Code">πŸ’»</a> <a href="#ideas-IlyaSemenov" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=IlyaSemenov" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://codechecks.io"><img src="https://avatars2.githubusercontent.com/u/46399828?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Code Checks</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/pulls?q=is%3Apr+reviewed-by%3Acodechecks" title="Reviewed Pull Requests">πŸ‘€</a></td> <td align="center"><a href="http://www.nomiclabs.io"><img src="https://avatars1.githubusercontent.com/u/176499?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Patricio Palladino</b></sub></a><br /><a href="#ideas-alcuadrado" title="Ideas, Planning, & Feedback">πŸ€”</a></td> <td align="center"><a href="http://twitter.com/quezak2"><img src="https://avatars0.githubusercontent.com/u/666206?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artur Kozak</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=quezak" title="Code">πŸ’»</a> <a href="#ideas-quezak" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=quezak" title="Documentation">πŸ“–</a> <a href="https://github.com/krzkaczor/ts-essentials/pulls?q=is%3Apr+reviewed-by%3Aquezak" title="Reviewed Pull Requests">πŸ‘€</a></td> <td align="center"><a href="https://github.com/lucifer1004"><img src="https://avatars2.githubusercontent.com/u/13583761?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zihua Wu</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=lucifer1004" title="Code">πŸ’»</a> <a href="#ideas-lucifer1004" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=lucifer1004" title="Documentation">πŸ“–</a></td> <td align="center"><a href="http://kevinpeno.com"><img src="https://avatars1.githubusercontent.com/u/343808?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peno</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=kevinpeno" title="Code">πŸ’»</a></td> <td align="center"><a href="https://github.com/DomParfitt"><img src="https://avatars2.githubusercontent.com/u/11363907?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dom Parfitt</b></sub></a><br /><a href="#ideas-DomParfitt" title="Ideas, Planning, & Feedback">πŸ€”</a></td> </tr> <tr> <td align="center"><a href="https://github.com/EduardoRFS"><img src="https://avatars0.githubusercontent.com/u/3393115?v=4?s=100" width="100px;" alt=""/><br /><sub><b>EduardoRFS</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=EduardoRFS" title="Code">πŸ’»</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=EduardoRFS" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://andydvorak.net/"><img src="https://avatars1.githubusercontent.com/u/409245?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew C. Dvorak</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=acdvorak" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/a1russell"><img src="https://avatars0.githubusercontent.com/u/241628?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adam Russell</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=a1russell" title="Code">πŸ’»</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=a1russell" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/sz-piotr"><img src="https://avatars2.githubusercontent.com/u/17070569?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piotr Szlachciak</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=sz-piotr" title="Code">πŸ’»</a> <a href="#ideas-sz-piotr" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=sz-piotr" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/mikhailswift"><img src="https://avatars3.githubusercontent.com/u/3218582?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mikhail Swift</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=mikhailswift" title="Code">πŸ’»</a></td> <td align="center"><a href="https://github.com/DevilZh"><img src="https://avatars1.githubusercontent.com/u/10295215?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ryan Zhang</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=DevilZh" title="Code">πŸ’»</a> <a href="#ideas-DevilZh" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=DevilZh" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://www.linkedin.com/in/francesco-borzi/"><img src="https://avatars1.githubusercontent.com/u/75517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Francesco BorzΓ¬</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=FrancescoBorzi" title="Documentation">πŸ“–</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=FrancescoBorzi" title="Code">πŸ’»</a></td> </tr> <tr> <td align="center"><a href="https://github.com/leaumar"><img src="https://avatars2.githubusercontent.com/u/3950300?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marnick L'Eau</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=leaumar" title="Code">πŸ’»</a> <a href="#ideas-leaumar" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=leaumar" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/kubk"><img src="https://avatars1.githubusercontent.com/u/22447849?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kubk</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=kubk" title="Code">πŸ’»</a></td> <td align="center"><a href="https://github.com/bbarry"><img src="https://avatars0.githubusercontent.com/u/84951?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bill Barry</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=bbarry" title="Code">πŸ’»</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=bbarry" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/akwodkiewicz"><img src="https://avatars2.githubusercontent.com/u/22861194?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrzej WΓ³dkiewicz</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=akwodkiewicz" title="Code">πŸ’»</a> <a href="https://github.com/krzkaczor/ts-essentials/commits?author=akwodkiewicz" title="Documentation">πŸ“–</a> <a href="#ideas-akwodkiewicz" title="Ideas, Planning, & Feedback">πŸ€”</a></td> <td align="center"><a href="http://chjdev.com"><img src="https://avatars2.githubusercontent.com/u/973941?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian</b></sub></a><br /><a href="#ideas-chjdev" title="Ideas, Planning, & Feedback">πŸ€”</a></td> <td align="center"><a href="https://github.com/mattleff"><img src="https://avatars0.githubusercontent.com/u/120155?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matthew Leffler</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=mattleff" title="Documentation">πŸ“–</a></td> <td align="center"><a href="https://github.com/studds"><img src="https://avatars2.githubusercontent.com/u/3046407?v=4?s=100" width="100px;" alt=""/><br /><sub><b>studds</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=studds" title="Code">πŸ’»</a></td> </tr> <tr> <td align="center"><a href="https://github.com/Beraliv"><img src="https://avatars.githubusercontent.com/u/2991847?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alex Berezin</b></sub></a><br /><a href="https://github.com/krzkaczor/ts-essentials/commits?author=Beraliv" title="Code">πŸ’»</a></td> </tr> </table> <!-- markdownlint-restore --> <!-- prettier-ignore-end --> <!-- ALL-CONTRIBUTORS-LIST:END --> This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! [Read more](./CONTRIBUTING.md)