Skip to content

Instantly share code, notes, and snippets.

@dishuostec
Last active March 31, 2022 05:43
Show Gist options
  • Save dishuostec/2a3500594efa6b57cb5a0ae593b67dc4 to your computer and use it in GitHub Desktop.
Save dishuostec/2a3500594efa6b57cb5a0ae593b67dc4 to your computer and use it in GitHub Desktop.
Typescript utility types
/**
* ObjectKeys
* @desc Extract name from type or class
* @param T type to analyze
* @param MatchType type to keep. Default is any - all types be included
* @param Reverse reverse match. Default is false
* @example
* class SimpleClass {
* static ZERO = 0;
* readonly one: string = '1';
* readonly two: string = '2';
* readonly three: number = 3;
* getOne(): string { return this.one; }
* getTwo(): string { return this.two; }
* }
*
* // be: "one" | "two" | "three" | "getOne" | "getTwo"
* type SC_AllNames = ObjectKeys<SimpleClass>; // like keyof SimpleClass
*
* // be: "one" | "two"
* type SC_StringNames = ObjectKeys<SimpleClass, string>;
*
* // be: "getOne" | "getTwo"
* type SC_FunctionNames = ObjectKeys<SimpleClass, Function>;
*
* // be: "three" | "getOne" | "getTwo"
* type SC_NonStringNames = ObjectKeys<SimpleClass, string, true>;
*
* // be: "one" | "two" | "three" | "getOne" | "getTwo" | "prototype" | "ZERO"
* type SC_AllNamesWithStatic = ObjectKeys<SimpleClass & typeof SimpleClass>;
*
* @see https://github.com/reforms/ts-types/blob/master/src/ts/ts_type_buildin_over.ts
*/
export type ObjectKeys<T, MatchType = any, Reverse extends boolean = false> = {
[K in keyof T]: T[K] extends MatchType
? Reverse extends true
? never
: K
: Reverse extends true
? K
: never
}[keyof T];
/**
* ObjectAssign
* @desc From `U` assign properties to `T` (just like object assign)
* @example
* type Props = { name: string; age: number; visible: boolean };
* type NewProps = { age: string; other: string };
*
* // Expect: { name: string; age: string; visible: boolean; other: string; }
* type ExtendedProps = ObjectAssign<Props, NewProps>;
*
* @see https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts
*/
export type ObjectAssign<T extends object, U extends object, I = Omit<T, keyof U> & Pick<U, keyof U & keyof T> & Omit<U, keyof T>> = Pick<I, keyof I>;
// https://github.com/livelybone/union-tuple/blob/c05f3bf4c9/index.d.ts
export type UnionPop<U> = (
(U extends any ? (k: (x: U) => void) => void : never) extends (k: infer I) => void
? I
: never
) extends { (a: infer A): void }
? A
: never
export type TuplePrepend<T extends any[], E> =
((a: E, ...r: T) => void) extends (...r: infer R) => void
? R
: never
type UnionToTupleRecursively<Union, Result extends any[]> = {
1: Result
0: UnionToTupleRecursively<Exclude<Union, UnionPop<Union>>,
TuplePrepend<Result, UnionPop<Union>>>
}[[Union] extends [never] ? 1 : 0]
export type UnionToTuple<U> = UnionToTupleRecursively<U, []>
export type TupleToUnion<T> = T extends (infer E)[] ? E : never
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment