Skip to content

Instantly share code, notes, and snippets.

@liamross
Last active January 23, 2020 02:12
Show Gist options
  • Save liamross/a563ddca696da3b905c2fca27f2a94e2 to your computer and use it in GitHub Desktop.
Save liamross/a563ddca696da3b905c2fca27f2a94e2 to your computer and use it in GitHub Desktop.
Custom types for working with complex TypeScript types.
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* Remove the specified Keys of T. Like Omit, but with autocompletion.
*
* @example
* type SomeProps = {field1: string; field2: string};
* const x: Remove<SomeProps, 'field2'> = {field1: 'Hello, World!'};
*/
export type Remove<T, Keys extends keyof T> = Pick<T, Exclude<keyof T, Keys>>;
/**
* Include only the specified Keys of T.
*
* @example
* type SomeProps = {field1: string; field2: string};
* const x: Include<SomeProps, 'field2'> = {field2: 'Hello, World!'};
*/
export type Include<T, Keys extends keyof T> = Pick<T, Extract<keyof T, Keys>>;
/**
* Require only the specified Keys of T.
*
* @example
* type SomeProps = {field1?: string; field2?: string};
* const x: RequireSome<SomeProps, 'field2'> = {field2: 'Hello, World!'};
*/
export type RequireSome<T, Keys extends keyof T> = Required<Include<T, Keys>> & Remove<T, Keys>;
/**
* Require all but the specified Keys of T.
*
* @example
* type SomeProps = {field1?: string; field2?: string};
* const x: RequireExcept<SomeProps, 'field2'> = {field1: 'Hello, World!'};
*/
export type RequireExcept<T, Keys extends keyof T> = Required<Remove<T, Keys>> & Include<T, Keys>;
/**
* Extract the common item type in array of similar items T.
*
* @example
* const x = [{a: 'a', b: 'b'}, {a: 'aa', b: 'bb'}];
* const y: ItemOf<typeof x> = {a: 'Hello'; b: 'World'};
*/
export type ItemOf<T extends any[]> = T[number];
/**
* Extracts an array of argument types of T.
*
* @example
* const x = (a: string, b: number) => a + b;
* const x: ArgumentTypes<typeof x> = ['Hello, World!', 100];
*/
export type ArgumentTypes<T extends Function> = T extends (...args: infer A) => any ? A : never;
/**
* Requires at least one of the specified Keys of T. If no keys provided, will
* require at least one of any keyof T.
*
* @example
* type SomeProps = {field1?: string; field2?: string};
* const x: RequireAtLeastOne<SomeProps, 'hello' | 'world'> = {field1: 'Hello, World!'};
*/
export type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Remove<T, Keys> &
{ [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> }[Keys];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment