// kind of any, but different => sometimes better for inference export type Any = boolean | string | number | object | symbol | null | undefined | any[]; // converts a tuple type (ex: [number, string]) to an union of types => 'number' | 'string' export type TupleTypes = { [P in keyof T]: T[P] } extends { [key: number]: infer V } ? V : never; // type A = TupleTypes<[1, "hello", true]>; // === 1 | "hello" | true // converts an union of types to an intersection of these types export type UnionToIntersection = (U extends any ? ((k: U) => void) : never) extends ((k: infer I) => void) ? I : never; // converts a tuple type to an intersections of these types export type TupleToIntersection = UnionToIntersection>; // converts a pure tuple to an array like tuple export type TupleArray = Array & TTuple; // removes from T (object) the properties K (union) export type Omit = Pick>; // removes from T (object) the properties K (tuple) export type ExcludeProperties = Pick>>; export type RequireProperties = Omit & Required>; export type PartialProperties = Omit & Partial>; // export type RequireProperties = T & { // [P in K]-?: T[P]; // }; export type Clone = { [K in keyof T]: T[K] }; // https://github.com/Microsoft/TypeScript/issues/9252#issuecomment-472881853 // creates an intersection between T and U export type Subset = { [key in keyof T]: key extends keyof U ? T[key] : never }; export type SuperSet = { [key in keyof T]: key extends keyof U ? (U[key] extends T[key] ? T[key] : never) : T[key] }; export type Extends = Clone extends B ? true : false; export type Not = A extends true ? false : true; export type And = A extends true ? B extends true ? true : false : false; export type TObject = { [key in any]: any }; // https://github.com/Microsoft/TypeScript/issues/26223 // https://github.com/ksxnodemodules/typescript-tuple/blob/master/lib/utils.ts export type ToTuple = { [K in Extract]: T[K]; }; export type IsEmptyTuple = Tuple extends [] ? true : false; // const a1: IsEmptyTuple<[]> = true; // const a2: IsEmptyTuple<[1]> = false; /** * Returns 'Finite' if the tuple is Finite, else returns 'Infinite' */ export type TupleIsFinite = { empty: Finite nonEmpty: ((...list: Tuple) => any) extends ((first: infer First, ...rest: infer Rest) => any) ? TupleIsFinite : never infinite: Infinite }[ Tuple extends [] ? 'empty' : Tuple extends (infer Item)[] ? Item[] extends Tuple ? 'infinite' : 'nonEmpty' : never ]; // const a1: IsFinite<[], true, false> = true; // const a2: IsFinite = false; /** * Creates a union from the types of an Array or tuple */ export type TupleToUnion = Tuple[number]; /** * Returns the length of an array or tuple */ export type TupleLength = Tuple['length']; /** * Returns all but the first item's type in a tuple/array */ export type TupleShift = ((...list: Tuple) => any) extends ((first: any, ...rest: infer R) => any) ? R : never; /** * Returns the given tuple/array with the item type prepended to it */ export type TupleUnshift = ((first: Item, ...rest: Tuple) => any) extends ((...list: infer R) => any) ? R : never; /** * Reverses items of a tuple */ export type TupleReverse = { empty: Prefix, nonEmpty: ((...list: Tuple) => any) extends ((first: infer First, ...rest: infer Rest) => any) ? TupleReverse> : never infinite: Array & { ERROR: 'Cannot reverse an infinite tuple' CODENAME: 'InfiniteTuple' } }[ // Tuple extends [any, ...any[]] // ? TupleIsFinite // : 'empty' Tuple extends [] ? 'empty' : TupleIsFinite ]; // const a: TupleReverse<[1, 2]>; // const a: TupleReverse<[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]>; // const a: TupleReverse; // export type TuplePush = T & { // [K in Extract]: Item; // }; // export type TuplePush> = { // [K in keyof R]: T[Extract]; // }; export type TuplePush = TupleReverse, Item>> // const a: TuplePush<[1, 2], 3>; export type TupleConcat = { emptyLeft: Right singleLeft: Left extends [infer Item] ? TupleUnshift : never multiLeft: ((...list: TupleReverse) => any) extends ((first: infer LeftLast, ...rest: infer ReversedLeftRest) => any) ? TupleConcat, TupleUnshift> : never infiniteLeft: Array & { ERROR: 'Left is not finite', CODENAME: 'InfiniteLeft' & 'Infinite' } }[ Left extends [] ? 'emptyLeft' : Left extends [any] ? 'singleLeft' : TupleIsFinite ]; // const a: TupleConcat<[1, 2], [3, 4]>; // const a: TupleReverse<[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]>; // const a: TupleReverse; export type TupleEquals = [T] extends [S] ? ( [S] extends [T] ? true : false ) : false; export type CreateRange = { 0: T, 1: CreateRange>>, }[TupleEquals>, N> extends true ? 0 : 1]; export type TupleFirst = Tuple extends [any, ...any[]] ? Tuple[0] : Default export type TupleLast = { empty: Default single: Tuple extends [infer Item] ? Item : never multi: ((...list: Tuple) => any) extends ((first: any, ...rest: infer Next) => any) ? TupleLast : Default infinite: Tuple extends (infer Item)[] ? Item : never }[ Tuple extends [] ? 'empty' : Tuple extends [any] ? 'single' : Tuple extends (infer Item)[] ? Item[] extends Tuple ? 'infinite' : 'multi' : never ] // const a: TupleShift<[1, 2]>; // const a: TupleUnshift<[1, 2], 3>; // const a: TupleLast<[1, 2]>; // const a: TuplePush<[1, 2], 3>; // const b = a[6]; // a[1] = 5; // const a: CreateRange<10>; /** * Tests if two types are equal */ type Equals = [T] extends [S] ? ( [S] extends [T] ? true : false ) : false; // export type IsSubSet = Clone extends TReferenceSet export type IsSubSet = [TSet] extends [TReferenceSet] ? true : false; export type IsSuperSet = IsSubSet; export type IsEqualSet = [TSet1] extends [TSet2] ? Clone extends TSet1 ? true : false : false; // export type IsSuperSet = UnionToIntersection extends UnionToIntersection // ? Clone extends UnionToIntersection // ? false // : true // : Clone extends UnionToIntersection // ? true // : false; // export type IsSuperSet = UnionToIntersection extends UnionToIntersection // ? Not>> // : Extends>; export type IsIntersecting = true extends ( TSet extends TReferenceSet ? true : TReferenceSet extends TSet ? true : false ) ? true : false; export type IsIntersection = // extends PropertyKey Clone extends T ? false : true; export type IsUnion = [T] extends [UnionToIntersection] ? false : Not>; export type IsSingleton = Clone extends T ? [T] extends [UnionToIntersection] ? true : false : false; export type IsType = false extends ( TargetType extends T ? T extends TargetType ? true : false : false ) ? false : true; // export type IsReadonly = T extends { // readonly [P in K]: T[P]; // } ? true : false; // // // const a1: { a: string } extends { readonly a: string } ? true : false = true; // const a2: { readonly a: string } extends { a: string } ? true : false = true; // const a3: readonly [string] extends [string] ? true : false = false; // const a4: [string] extends readonly [string] ? true : false = true; // const a5: readonly [string] extends readonly [string] ? true : false = true; // // const a: IsReadonly<{ a: string }, 'a'> = false; // const y0: IsType = false; // const y1: IsType = false; // const y2: IsType = true; // const y3: IsType = true; // const y4: IsType = false; // const b0: IsSubSet<'a', 'a' | 'b'> = true; // const b1: IsSubSet<'a' | 'b', 'a' | 'b' | 'c'> = true; // const b2: IsSubSet<'a' | 'b' | 'c', 'a' | 'b'> = false; // const b3: IsSubSet<'a' | 'd', 'a' | 'b'> = false; // const b4: IsSubSet<'a' | 'b', string> = true; // const b5: IsSubSet = false; // const b6: IsSubSet<'a' | 'b', 'a' | 'b'> = true; // const b7: IsSubSet = true; // const a0: IsSuperSet<'a' | 'b', 'a'> = true; // const a1: IsSuperSet<'a' | 'b' | 'c', 'a' | 'b'> = true; // const a2: IsSuperSet<'a' | 'b', 'a' | 'b' | 'c'> = false; // const a3: IsSuperSet<'a' | 'b', 'a' | 'd'> = false; // const a4: IsSuperSet = true; // const a5: IsSuperSet<'a' | 'b', string> = false; // const a6: IsSuperSet<'a' | 'b', 'a' | 'b'> = true; // const c0: IsIntersecting<'a' | 'b', 'a'> = true; // const c1: IsIntersecting<'a' | 'b', 'a' | 'c'> = true; // const c2: IsIntersecting<'a', 'a' | 'c'> = true; // const c3: IsIntersecting<'a', 'b' | 'c'> = false; // const c4: IsIntersecting<'b' | 'c', 'a'> = false; // const c5: IsIntersecting = true; // const c6: IsIntersecting<'a', string> = true; // const c7: IsIntersecting<1 | 3, number> = true; // const i0: IsIntersection<'a'> = false; // const i1: IsIntersection<'a' | 'b'> = false; // const i2: IsIntersection<'a' & 'b'> = true; // // const u0: IsUnion<'a'> = false; // const u1: IsUnion<'a' | 'b'> = true; // const u2: IsUnion<'a' & 'b'> = false; // // const s0: IsSingleton<'a'> = true; // const s1: IsSingleton<'a' | 'b'> = false; // const s2: IsSingleton<'a' & 'b'> = false; // // const z0: IsType = true; // const z1: IsType = false; // const z2: IsType = true; // const a: keyof ('a' & 'b'); // const a: keyof ('a' | 'b'); // const a: (string extends ('a' | 'b') ? true : false); // const a: (string extends ('a' & 'b') ? true : false); // => false // const a: (('a' & 'b') extends string ? true : false); // => true // ('a' & 'b' & 'c') extends ('a' & 'b') => true // https://stackoverflow.com/questions/51691235/typescript-map-union-type-to-another-union-type // how to map a union type to another // export type Distribute = U extends any ? {type: U} : never; // // if T = { a: 1, b: 2 }, and U = { a: 1, b: 2, c: 3 } // export type SuperSet2 = { // // keyof T = 'a' | 'b' // // keyof U = 'a' | 'b' | 'c' // // key = 'a', 'b' // [key in keyof T]: key extends keyof U // ? (U[key] extends T[key] ? T[key] : never) // : T[key] // }; // // // type A1 = ('a' | 'b' | 'c') extends ('a' | 'b') ? boolean : never; // => never // type A2 = 'a'/* | 'b'*/ extends ('a' | 'b') ? boolean : never; // => boolean // // with unions, extends behaves like a 'is sub set' // // type A3 = SuperSet<{ a: 1, b: 2, g: 1 }, { a: 1, b: 2, c: 3 }>;