HTWiki🌔

type-challenges


#Type challenges

My type challenges speed run.

#object

  • Partial
  • Required
  • Readonly
  • Record
  • Pick
  • Omit
  • NonNullable
  • class
    • ConstructorParameters
    • InstanceType
    • ThisParameterType
    • OmitThisParameter
    • ThisType

#Pick

type MyPick<T, K extends keyof T> = {
  [Key in K]: T[Key];
}

#Readonly

type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
}

#Tuple to Object

type TupleToUnion<T extends unknown[]> = T[number];
type TupleToObject<T extends readonly string[]> = {
  [K in TupleToUnion<T>]: K;
}

#Omit

type MyOmit<T, K> = {
  [Key in Exclude<keyof T, K>]: T[Key];
}

#Readonly 2

type Merge<T> = {
  [K in keyof T]: T[K];
}
type MyReadonly2<T, K extends keyof T = keyof T>
  = Merge<Readonly<Pick<T, K>> & Omit<T, K>>;

#Deep Readonly

type DeepReadonly<T> = T extends string|number|boolean|Function ? T : {
  readonly [K in keyof T]: DeepReadonly<T[K]>;
}

#Chainable Options

type Merge<T> = {
  [K in keyof T]: T[K];
}
type Chainable<T = {}> = {
  option<K extends string, V>(key: K, value: V): Chainable<Merge<T & Record<K, V>>>;
  get(): T;
}

#Append to object

type Merge<T> = {
  [K in keyof T]: T[K];
}
type AppendToObject<T, U extends string, V> = Merge<T & {[K in U]: V}>;

#Merge

type Merge<F, S> = {
  [K in keyof F | keyof S]: K extends keyof S
    ? S[K]
    : K extends keyof F ? F[K] : never;
};

#Diff

type Merge<T> = {
  [K in keyof T]: T[K];
}
type Diff<T, U> = Merge<Omit<T, keyof U> & Omit<U, keyof T>>;

#ReplaceKeys

type ReplaceKeys<U, T, Y> = {
  [K in keyof U]: K extends T
    ? (K extends keyof Y ? Y[K] : never)
    : U[K];
}

#Remove Index Signature

type LiteralOnly<T> = string extends T ? never : number extends T ? never : T;
type RemoveIndexSignature<T> = {
  [K in keyof T as LiteralOnly<K>]: T[K];
};

#PickByType

type PickByType<T, U> = {
  [K in keyof T as T[K] extends U ? K : never]: T[K];
}

#PartialByKeys

type Merge<T> = {
  [K in keyof T]: T[K];
}
type MyPick<T, K> = {
  [Key in keyof T as Key extends K ? Key : never]: T[Key];
}
type PartialByKeys<T, K extends string|number|symbol = keyof T>
  = Merge<Partial<MyPick<T, K>> & Omit<T, K>>;

#RequiredByKeys

type Merge<T> = {
  [K in keyof T]: T[K];
}
type MyPick<T, K> = {
  [Key in keyof T as Key extends K ? Key : never]: T[Key];
}
type RequiredByKeys<T, K extends string|number|symbol = keyof T>
  = Merge<Required<MyPick<T, K>> & Omit<T, K>>;

#Mutable

type Mutable<T> = T extends Readonly<infer R> ? R : T;
type Mutable<T> = {
  -readonly [K in keyof T]: T[K];
}

#OmitByType

type OmitByType<T, U> = {
  [K in keyof T as T[K] extends U ? never : K]: T[K];
}

#ObjectEntries

type Dist<T, K extends keyof T = keyof T> = K extends K ? [K, T[K]] : never;
type ObjectEntries<T> = Dist<Required<T>>;

how to invert object's key value?

type Pairs<T, K extends keyof T = keyof T> = K extends K ? [K, T[K]] : never;
type ReversedObject<T extends Record<PropertyKey, PropertyKey>> = {
    [P in Pairs<T> as P[0]]: P[1];
}

#InorderTraversal

type InorderTraversal<T> = T extends {val: infer V, left: infer TL, right: infer TR}
  ? [...InorderTraversal<TL>, V, ...InorderTraversal<TR>]
  : [];

#Flip

type Flip<T extends Record<string, string|boolean|number>> = {
  [K in keyof T as `${T[K]}`]: K;
}

#MapTypes

type Dist<T, V> = T extends {mapFrom: V} ? T : never;
type MapTypes<T, R extends {mapFrom: unknown, mapTo: unknown}> = {
  [K in keyof T]: Dist<R, T[K]> extends never ? T[K] : Dist<R, T[K]>['mapTo']
}

#Simple Vue

type MapReturnType<T> = {
  [K in keyof T]: T[K] extends (...args: unknown[]) => infer R ? R : never
}
declare function SimpleVue<D, C, M>(options: {
  data?(): D;
  computed: C & ThisType<D>;
  methods?: M & ThisType<D & M & MapReturnType<C>>;
}): unknown;

??? this type https://www.typescriptlang.org/docs/handbook/utility-types.html#thistypetype

#Get Required

type GetRequired<T> = {
  [K in keyof T as Pick<T, K> extends Required<Pick<T, K>> ? K : never]: T[K]
}

#Get Optional

type GetOptional<T> = {
  [K in keyof T as Pick<T, K> extends Required<Pick<T, K>> ? never : K]: T[K]
}

#Required Keys

type GetRequired<T> = {
  [K in keyof T as Pick<T, K> extends Required<Pick<T, K>> ? K : never]: T[K]
}
type RequiredKeys<T> = keyof GetRequired<T>;

#Optional Keys

type GetOptional<T> = {
  [K in keyof T as Pick<T, K> extends Required<Pick<T, K>> ? never : K]: T[K]
}
type OptionalKeys<T> = keyof GetOptional<T>;

#Vue Basic Props

type Constructor<T> = new (...args: any[]) => T;
type ConvertType<T> =
  T extends StringConstructor
    ? string :
    T extends BooleanConstructor
      ? boolean :
      T extends NumberConstructor
        ? number
        : T extends Constructor<unknown>
          ? InstanceType<T>
          : T;
type GetType<T> =
  T extends {type: infer P}
    ? P extends unknown[]
      ? ConvertType<P[number]>
      : ConvertType<P>
    : T extends Constructor<unknown>
      ? InstanceType<T>
      : T;
type MapProps<T> = {
  [K in keyof T]: GetType<T[K]>;
}
type MapReturnType<T> = {
  [K in keyof T]: T[K] extends (...args: unknown[]) => infer R ? R : never
}
declare function VueBasicProps<P, D, C, M>(options: {
  props: P;
  data(this: MapProps<P>): D;
  computed: C & ThisType<D&MapProps<P>>;
  methods: M & ThisType<MapProps<P> & D & MapReturnType<C> & M>;
}): unknown

#Deep object to unique

declare const KEY: unique symbol;

type DeepObjectToUniq<O, Parent = O, Path extends readonly PropertyKey[] = []> = {
  [K in keyof O]: O[K] extends object
    ? DeepObjectToUniq<O[K], O, [...Path, K]>
    : O[K];
} & {
  readonly [KEY]?: readonly [Parent, Path];
};

#DeepPick

type Get<T, K> = K extends `${infer P}.${infer Rest}`
  ? P extends keyof T ? {[Key in P]: Get<T[P], Rest>} : never
  : K extends keyof T ? {[Key in K]: T[K]} : never;
type DeepPick<T, P> = UnionToIntersect<Get<T, P>>;

#Pinia

type MapReturnType<T> = {
  [K in keyof T]: T[K] extends (...args: unknown[]) => infer R ? R : never
}
declare function defineStore<S, G, A>(store: {
  id: string;
  state(): S;
  getters: G & ThisType<Readonly<S & MapReturnType<G>>>;
  actions: A & ThisType<S & Readonly<MapReturnType<G>> & A>;
}): Readonly<S & MapReturnType<G> & A>;

#ClassPublicKeys

type ClassPublicKeys<T> = keyof T;

#IsRequiredKey

type GetRequired<T> = {
  [K in keyof T as Pick<T, K> extends Required<Pick<T, K>> ? K : never]: T[K]
}
type RequiredKeys<T> = keyof GetRequired<T>;
// Prevent union type dist
type IsRequiredKey<T, K extends keyof T> = [K] extends [RequiredKeys<T>] ? true : false;

#ObjectFromEntries

type StringOnly<T> = T extends string ? T : never;
type GetN<T, N extends number = 0> = T extends unknown[] ? T[N] : never;
type ObjectFromEntries<T> = {
  [P in T as StringOnly<GetN<P>>]: GetN<P, 1>;
}
type ObjectFromEntries<T extends [string, unknown]> = {
  [K in T as K[0]]: K[1];
}

similar to ObjectEntries

#Mutable Keys

type GetMutable<T> = {
  [K in keyof T as Equal<Readonly<Pick<T, K>>, Pick<T, K>> extends true ? never : K]: T[K];
}
type MutableKeys<T> = keyof GetMutable<T>;

#Get Readonly Keys

type GetReadonly<T> = {
  [K in keyof T as Equal<Readonly<Pick<T, K>>, Pick<T, K>> extends true ? K : never]: T[K]
}
type GetReadonlyKeys<T> = keyof GetReadonly<T>;

#array / tuple

#First of Array

type First<T extends unknown[]> = T extends [infer F, ...infer _] ? F : never;

#Length of Tuple

type Length<T extends readonly unknown[]> = T['length'];

#Concat

type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];
  • thinking when object spread will be supported?

#Includes

type Includes<T extends readonly unknown[], U> = T extends [infer F, ...infer Rest]
  ? Equal<F, U> extends true ? true : Includes<Rest, U>
  : false;

#Push

type Push<T extends unknown[], U> = [...T, U];

#Unshift

type Unshift<T extends unknown[], U> = [U, ...T];

#Tuple to Union

type TupleToUnion<T extends unknown[]> = T[number];

#Last of Array

type Last<T extends unknown[]> = T extends [...infer V, infer Last] ? Last : never;

#Pop

type Pop<T> = T extends [...infer Rest, infer _] ? Rest : [];

#Flatten

type Flatten<T> = T extends []
  ? T
  : T extends [infer First, ...infer Rest] ? [...Flatten<First>, ...Flatten<Rest>] : [T];

#AnyOf

type Truthy<T> = Equal<T, {}> extends true ? never : T extends 0|''|false|[] ? never : true;
type AnyOf<T extends readonly unknown[]> = T extends [infer First, ...infer Rest]
  ? true extends Truthy<First> ? true : AnyOf<Rest>
  : false;
type AnyOf<T extends readonly unknown[]> =
  T[number] extends 0 | '' | false | [] | Record<string, never> ? false : true;

#MinusOne

type TupleOfLength<T, Result extends unknown[] = []> =
  Result['length'] extends T ? Result : TupleOfLength<T, [...Result, 0]>;
type MinusOne<T extends number> =
  TupleOfLength<T> extends [infer First, ...infer Rest] ? Rest['length'] : never;

#Shift

type Shift<T> = T extends [infer First, ...infer Rest] ? Rest : T;

#Tuple to Nested Object

type TupleToNestedObject<T, U> = T extends [infer First, ...infer Rest]
  ? {[K in First as K extends string ? K : never]: TupleToNestedObject<Rest, U>}
  : U;

#Reverse

type Reverse<T> = T extends [infer First, ...infer Rest] ? [...Reverse<Rest>, First] : T;

#FlattenDepth

type FlattenDepth<T extends unknown[], N = 1, Acc extends unknown[] = []> =
  T extends [infer F, ...infer Rest]
    ? Acc['length'] extends N
      ? T
      : F extends unknown[]
        ? [...FlattenDepth<F, N, [...Acc, 0]>, ...FlattenDepth<Rest, N, Acc>]
        : [F, ...FlattenDepth<Rest, N, Acc>]
    : [];
type FlattenDepth<T, N = 1, Acc extends unknown[] = []> =
  T extends [infer F, ...infer Rest]
    ? Acc['length'] extends N
      ? T
      : [...FlattenDepth<F, N, [...Acc, 0]>, ...FlattenDepth<Rest, N, Acc>]
    : T;

#Fibonacci Sequence

// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
type Fibonacci<T extends number, Acc extends number[][] = [[], [0]]> = Acc extends [...infer Rest, infer F, infer S]
  ? Rest['length'] extends T
    ? F extends number [] ? F['length'] : never
    : F extends number[] ? S extends number[] ? Fibonacci<T, [...Acc, [...F, ...S]]> : never : never
  : never;

#Greater Than

type TupleOfLength<T, Result extends unknown[] = []> =
  Result['length'] extends T ? Result : TupleOfLength<T, [...Result, 0]>;
type MinusOne<T extends number> =
  TupleOfLength<T> extends [infer First, ...infer Rest] ? Rest['length'] : never;
type GreaterThan<T extends number, U extends number> =
  T extends 0 ? false : U extends 0 ? true : GreaterThan<MinusOne<T>, MinusOne<U>>;

#Zip

type Zip<T extends unknown[], U extends unknown[]> = T extends [infer TF, ...infer TRest]
  ? (U extends [infer UF, ...infer URest] ? [[TF, UF], ...Zip<TRest, URest>] : [])
  : [];
type Zip<T extends unknown[], U extends unknown[]> =
  [T, U] extends [[infer L, ...infer RestT], [infer R, ...infer RestU]]
    ? [[L, R], ...Zip<RestT, RestU>]
    : [];

#Chunk

type Chunk<T extends unknown[], L, Acc extends unknown[] = []> =  Acc['length'] extends L
  ? [Acc, ...Chunk<T, L, []>]
  : T extends [infer First, ...infer Rest]
    ? Chunk<Rest, L, [...Acc, First]>
    : Acc extends [] ? [] : [Acc];

#Fill

type Fill<
  T extends unknown[],
  N,
  Start extends number = 0,
  End extends number = T['length'],
  Result extends unknown[] = [],
  Flag = false
> = Flag extends true
  ? Result['length'] extends End
    ? [...Result, ...T]
    : T extends [infer F, ...infer Rest]
      ? Fill<Rest, N, Start, End, [...Result, N], true>
      : Result
  : Result['length'] extends Start
    ? Fill<T, N, Start, End, Result, true>
    : T extends [infer F, ...infer Rest]
      ? Fill<Rest, N, Start, End, [...Result, F], false>
      : Result;

#Without

type ToUnion<T> = T extends unknown[] ? T[number] : T;
type Without<T, U> = T extends [infer F, ...infer Rest]
  ? F extends ToUnion<U> ? Without<Rest, U> : [F, ...Without<Rest, U>]
  : T;

#IndexOf

type IndexOf<T, U> = T extends [...infer Rest, infer L]
  ? L extends U
    ? IndexOf<Rest, U> extends -1
      ? Rest['length']
      : IndexOf<Rest, U>
    : IndexOf<Rest, U>
  : -1;
type IndexOf<T, U, Acc extends unknown[] = []> = T extends [infer F, ...infer Rest]
  ? F extends U ? Acc['length'] : IndexOf<Rest, U, [...Acc, F]>
  : -1;

#LastIndexOf

type LastIndexOf<T, U> = T extends [...infer Rest, infer L]
    ? L extends U ? Rest['length'] : LastIndexOf<Rest, U>
    : -1;

#Unique

type Unique<T, Seen = never> = T extends [infer F, ...infer Rest]
  ? F extends Seen ? Unique<Rest, Seen> : [F, ...Unique<Rest, Seen|F>]
  : [];

#Promise.all

type UnPromise<T> = T extends Promise<infer P> ? P : T;
type UnPromiseList<T> = T extends [infer F, ...infer Rest] ? [UnPromise<F>, ...UnPromiseList<Rest>] : [];
declare function PromiseAll<T extends unknown[]>(values: readonly [...T]): Promise<UnPromiseList<T>>;
type UnPromise<T> = {
  [K in keyof T]: T[K] extends Promise<infer V> ? V : T[K];
}
declare function PromiseAll<T extends unknown[]>(values: readonly [...T]): Promise<UnPromise<T>>;

#Tuple Filter

type FilterOut<T extends unknown[], F> = T extends [infer First, ...infer Rest]
  ? [First] extends [F] ? FilterOut<Rest, F> : [First, ...FilterOut<Rest, F>]
  : [];

#Tuple to Enum Object

type Cap<T> = T extends string ? Capitalize<T> : never;
type GetNPair<T, Acc extends unknown[] = []>
  = T extends readonly [infer F, ...infer Rest]
    ? [[Cap<F>, Acc['length']], ...GetNPair<Rest, [...Acc, unknown]>]
    : [];
type GetKPair<T>
  = T extends readonly [infer F, ...infer Rest]
    ? [[Cap<F>, F], ...GetKPair<Rest>]
    : [];
type GetPair<T, N> = N extends true ? GetNPair<T> : GetKPair<T>;

type StringOnly<T> = T extends string ? T : never;
type GetN<T, N extends number = 0> = T extends unknown[] ? T[N] : never;
type ObjectFromEntries<T> = {
  [P in T as StringOnly<GetN<P>>]: GetN<P, 1>;
}
type Enum<T extends readonly string[], N extends boolean = false>
  = Readonly<ObjectFromEntries<GetPair<T, N>[number]>>;

#Slice

similar to Fill

type SlicePos<
  T extends unknown[],
  Start extends number = 0,
  End extends number = T['length'],
  Acc extends unknown[] = [],
  Flag = false
> = Flag extends true
  ? Acc['length'] extends End
    ? []
    : T extends [infer F, ...infer Rest]
      ? [F, ...SlicePos<Rest, Start, End, [...Acc, F], true>]
      : []
  : Acc['length'] extends Start
    ? SlicePos<T, Start, End, Acc, true>
    : T extends [infer F, ...infer Rest]
      ? SlicePos<Rest, Start, End, [...Acc, F], false>
      : [];

type Slice<
  T extends unknown[],
  Start extends number = 0,
  End extends number = T['length'],
> = SlicePos<T, MakePos<Start, T['length']>, MakePos<End, T['length']>>

#Integers Comparator

enum Comparison {
  Greater,
  Equal,
  Lower,
}
type IsNeg<T extends number> = `${T}` extends `-${infer _}` ? true : false;
type Abs<T extends number> = `${T}` extends `-${infer V}` ? V : `${T}`;
type Comp<A extends string, B extends string, Acc extends unknown[] = []> = A extends B
  ? Comparison.Equal
  : `${Acc['length']}` extends A
    ? Comparison.Lower
    : `${Acc['length']}` extends B
      ? Comparison.Greater
      : Comp<A, B, [...Acc, unknown]>;
type Comparator<A extends number, B extends number> = IsNeg<A> extends true
  ? IsNeg<B> extends true
    ? Comp<Abs<B>, Abs<A>>
    : Comparison.Lower
  : IsNeg<B> extends true
    ? Comparison.Greater
    : Comp<`${A}`, `${B}`>;

#function

  • Parameters
  • ReturnType

#Parameters

type MyParameters<T> = T extends (...args: infer Args) => unknown ? Args : never;

#Get Return Type

type MyReturnType<T> = T extends (...args: infer Args) => infer R ? R : never;

#Append Argument

type AppendArgument<Fn, A> = Fn extends (...args: infer Args) => infer R
  ? (...args: [...Args, A]) => R
  : Fn;

#Flip Arguments

type Reverse<T> = T extends [infer First, ...infer Rest] ? [...Reverse<Rest>, First] : T;
type FlipArguments<T> = T extends (...args: infer Args) => infer R ? (...args: Reverse<Args>) => R : T;
type FlipArguments<T extends (...args: any) => any> = (...args: Reverse<Parameters<T>>) => ReturnType<T>;

#Currying 1

type Curry<T> = T extends (...args: infer Args) => infer R
  ? Args extends [infer F, infer S, ...infer Rest]
    ? (x: F) => Curry<(...args: [S, ...Rest]) => R>
    : T
  : never;
declare function Currying<T>(fn: T): Curry<T>;

#Currying 2

type ArgsUnion<T extends unknown[]> = T extends [infer F, ...infer Rest]
  ? [F] | [F, ...ArgsUnion<Rest>]
  : [];
type Drop<T, N extends number, Acc extends unknown[] = []>
  = Acc['length'] extends N ? T : T extends [infer _, ...infer Rest] ? Drop<Rest, N, [...Acc, unknown]> : never;
type Curried<T> = T extends (...args: infer Args) => infer R
  ? <A extends ArgsUnion<Args>>(...args: A) => A extends Args
    ? R
    : Curried<(...args: Drop<Args, A['length']>) => R>
  : never;
declare function DynamicParamsCurrying<T>(fn: T): Curried<T>;

#string

  • Uppercase
  • Lowercase
  • Capitalize
  • Uncapitalize

#Typed Get

type Get<T, K> = K extends `${infer P}.${infer Rest}`
  ? Get<Get<T, P>, Rest>
  : K extends keyof T ? T[K] : never;

#Trim Left

type Space = ' '|'\n'|'\t';
type TrimLeft<S extends string> = S extends `${Space}${infer Rest}` ? TrimLeft<Rest> : S;

#Trim

type Space = ' '|'\n'|'\t';
type TrimLeft<S extends string> = S extends `${Space}${infer Rest}` ? TrimLeft<Rest> : S;
type TrimRight<S extends string> = S extends `${infer Rest}${Space}` ? TrimRight<Rest> : S;
type Trim<S extends string> = TrimRight<TrimLeft<S>>;

#Capitalize

type Capitalize<S extends string> = S extends `${infer C}${infer Rest}` ? `${Uppercase<C>}${Rest}` : S;

#Replace

type Replace<S extends string, From extends string, To extends string> = From extends ''
  ? S
  : S extends `${infer C}${From}${infer Rest}` ? `${C}${To}${Rest}` : S;

#ReplaceAll

type ReplaceAll<S extends string, From extends string, To extends string> = From extends ''
  ? S
  : S extends `${infer C}${From}${infer Rest}` ? `${C}${To}${ReplaceAll<Rest, From, To>}` : S;

#Length of String

type LengthOfString<S extends string, T extends unknown[] = []> =
  S extends `${infer C}${infer Rest}` ? LengthOfString<Rest, [...T, C]> : T['length'];

#Absolute

type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer V}` ? V : `${T}`;

#String to Union

type StringToUnion<T extends string> =
  T extends `${infer C}${infer Rest}` ? C|StringToUnion<Rest> : never;

#CamelCase

type CamelCase<S> = S extends `${infer First}-${infer C}${infer Rest}`
  ? Uppercase<C> extends C
    ? `${First}-${CamelCase<`${C}${Rest}`>}`
    : `${First}${Uppercase<C>}${CamelCase<Rest>}`
  : S;

#KebabCase

type KebabCase<S, D extends string = ''> = S extends `${infer C}${infer Rest}`
  ? C extends Lowercase<C>
    ? `${C}${KebabCase<Rest, '-'>}`
    : `${D}${Lowercase<C>}${KebabCase<Rest, '-'>}`
  : S;

#Percentage Parser

type MP = '+'|'-';
type P = '%';
type Sign<T> = T extends `${infer C}${infer Rest}`? C extends MP ? C : '' : '';
type Percentage<T> = T extends `${infer Rest}${P}`?  P : '';
type DropSign<T> = T extends `${MP}${infer Rest}` ? Rest : T;
type DropPercentage<T> = T extends `${infer Rest}%` ? Rest : T;
type PercentageParser<T> = [Sign<T>, DropPercentage<DropSign<T>>, Percentage<T>];

#Drop Char

type DropChar<S, C extends string> =
  S extends `${infer First}${C}${infer Last}` ? DropChar<`${First}${Last}`, C> : S;

#StartsWith

type StartsWith<T extends string, U extends string> = T extends `${U}${infer Rest}`? true : false;

#EndsWith

type EndsWith<T extends string, U extends string> = T extends `${infer Rest}${U}`? true : false;

#BEM style string

type Dist<T extends string, U extends string, D extends string> =
  [U] extends [never] ? T : U extends U ? `${T}${D}${U}` : never;
type BEM<B extends string, E extends string[], M extends string[]> =
  Dist<Dist<B, E[number], '__'>, M[number], '--'>;

#AllCombinations

type Permutation<T extends string, U extends string = T> = Equal<T, never> extends true
  ? ''
  : (T extends U ? `${T}${Permutation<Exclude<U, T>>}` : never);

type AllCombinations<S, Acc extends string = never> = S extends `${infer F}${infer Rest}`
  ? Permutation<Acc|F> | AllCombinations<Rest, Acc> | AllCombinations<Rest, Acc|F>
  : '';

???

type AllCombinations<S, Acc extends string = ''> = S extends `${infer F}${infer Rest}`
  ? `${F}${AllCombinations<`${Acc}${Rest}`>}` | AllCombinations<Rest, `${Acc}${F}`>
  : '';

literal template string matching behavior:

// Match all
type T = '' extends `${infer R}` ? R : never; // ''
type T = '1' extends `${infer R}` ? R : never; // '1'
type T = '12' extends `${infer R}` ? R : never; // '12'
// Match first char
type T = '' extends `${infer R}${infer Rest}` ? R : never; // never
type T = '1' extends `${infer R}${infer Rest}` ? R : never; // '1'
type T = '12' extends `${infer R}${infer Rest}` ? R : never; // '1'

#Trim Right

type Space = ' '|'\n'|'\t';
type TrimRight<S extends string> = S extends `${infer Rest}${Space}` ? TrimRight<Rest> : S;

#Trunc

type Trunc<T extends number|string> = `${T}` extends `${infer Rest}.${infer _}` ? Rest : `${T}`;

#Join

type Join<T, U extends string, D extends string = ''> = T extends [infer F, ...infer Rest]
  ? F extends string ? `${D}${F}${Join<Rest, U, U>}` : never
  : '';

#Capitalize Words

type CapitalizeWords<S extends string, Flag = true> =
  S extends `${infer F}${infer Rest}`
    ? Flag extends true
      ? `${Uppercase<F>}${CapitalizeWords<Rest, false>}`
      :  `${F}${CapitalizeWords<Rest, F extends ' '|','|'.' ? true : false>}`
    : '';
type FirstDivider<S> = S extends `${infer C}${infer Rest}` ?
  C extends ','|'.'|' ' ? C : FirstDivider<Rest>
  : never;

type CapitalizeWords<S extends string> =
  S extends `${infer W}${FirstDivider<S>}${infer Rest}` ?
  `${Capitalize<W>}${FirstDivider<S>}${CapitalizeWords<Rest>}`
  : Capitalize<S>;

#CamelCase

type CamelCase2<S, D extends string> = S extends `${infer First}${D}${infer C}${infer Rest}`
  ? Uppercase<C> extends C
    ? `${First}${D}${CamelCase<`${C}${Rest}`>}`
    : `${First}${Uppercase<C>}${CamelCase<Rest>}`
  : S;
type CamelCase<S extends string> = CamelCase2<Lowercase<S>, '_'>;

#C-printf Parser

type ParsePrintFormat<S, Prev = ''> = S extends `${infer F}${infer Rest}`
  ? Prev extends '%'
    ? F extends keyof ControlsMap
      ? [ControlsMap[F], ...ParsePrintFormat<Rest, ''>]
      : ParsePrintFormat<Rest, ''>
    : ParsePrintFormat<Rest, F>
  : [];

#String to Number

type ToNumber<S extends string, Acc extends unknown[] = []> =
  S extends `${Acc['length']}` ? Acc['length'] : ToNumber<S, [...Acc, 0]>;

#printf

type CMap = {
  's': string;
  'd': number;
}
type Format<T extends string, Prev = ''> = T extends `${infer F}${infer Rest}`
  ? Prev extends '%'
    ? F extends keyof CMap
      ? (x: CMap[F]) => Format<Rest, ''>
      : Format<Rest, ''>
    : Format<Rest, F>
  : string;

#Length of String 2

TODO:

  • trick

#String Join

type Join<T, U extends string, D extends string = ''> = T extends [infer F, ...infer Rest]
  ? F extends string ? `${D}${F}${Join<Rest, U, U>}` : never
  : '';
declare function join<D extends string>(delimiter: D): <T extends string[]>(...parts: T) => Join<T, D>;

#Camelize

type CamelCase2<S, D extends string> = S extends `${infer First}${D}${infer C}${infer Rest}`
  ? Uppercase<C> extends C
    ? `${First}${D}${CamelCase<`${C}${Rest}`>}`
    : `${First}${Uppercase<C>}${CamelCase<Rest>}`
  : S;
type CamelCase<S extends string> = CamelCase2<Lowercase<S>, '_'>;
type Camelize<T> = T extends unknown[]
  ? T extends [infer F, ...infer Rest]
    ? [Camelize<F>, ...Camelize<Rest>]
    : []
  : T extends string
    ? CamelCase<T>
    : {
      [K in keyof T as Camelize<K>]: Camelize<T[K]>;
    };

#Drop String

type StringToUnion<T extends string> =
  T extends `${infer C}${infer Rest}` ? C|StringToUnion<Rest> : never;
type DropString<S, R extends string > = S extends `${infer C}${infer Rest}`
  ? `${C extends StringToUnion<R> ? '' : C}${DropString<Rest, R>}`
  : S;

#Split

type Split<S, SEP extends string> = string extends S
  ? string[]
  : S extends `${infer F}${SEP}${infer Rest}`
    ? [F, ...Split<Rest, SEP>]
    : S extends SEP ? [] : [S];

#IsPalindrome

type IsPalindrome<T extends number|string>
  = `${T}` extends `${infer F}${infer _}`
    ? `${T}` extends F
      ? true
      : `${T}` extends `${F}${infer Rest}${F}` ? IsPalindrome<Rest> : false
    : false;

#Query String Parser

type Split<S, SEP extends string> = string extends S
  ? string[]
  : S extends `${infer F}${SEP}${infer Rest}`
    ? [F, ...Split<Rest, SEP>]
    : S extends SEP ? [] : [S];
type StringOnly<T> = T extends string ? T : never;
type ToObj<T extends unknown[]> =
  T extends [infer F, infer L]
    ? Record<StringOnly<F>, L>
    : T[0] extends '' ? {} : Record<StringOnly<T[0]>, true>;
type MapKV<T> = T extends [infer F, ...infer Rest] ? [ToObj<Split<F, '='>>, ...MapKV<Rest>] : [];
type ToPair<T> = MapKV<Split<T, '&'>>;
type Merge<O, T> = {
  [K in keyof T | keyof O]: K extends keyof T
    ? K extends keyof O
      ? O[K] extends T[K] ? T[K] : [O[K], T[K]]
      : T[K]
    : K extends keyof O ? O[K] : never;
}
type MergeObj<T> = T extends [infer F, ...infer Rest] ? Merge<F, MergeObj<Rest>> : {};
type ParseQueryString<T> = MergeObj<ToPair<T>>;

#others, union, intersection etc

  • Exclude
  • Extract

#Exclude

type MyExclude<T, U> = T extends U ? never : T;

#Awaited

type MyAwaited<T> = T extends Promise<infer V> ? MyAwaited<V> : T;
  • conditional
    • infer

#If

type If<C, T, F> = C extends true ? T : F;

#Type Lookup

type LookUp<U, T> = U extends {type: T} ? U : never;

#Permutation

type Permutation<T, U = T> = Equal<T, never> extends true
  ? []
  : (T extends U ? [T, ...Permutation<Exclude<U, T>>] : never);
type Permutation<T, U = T> = [T] extends [never]
  ? []
  : (T extends U ? [T, ...Permutation<Exclude<U, T>>] : never);

#IsNever

type IsNever<T> = Equal<never, T>;
type IsNever<T> = [T] extends [never] ? true : false;

#IsUnion

type NotEqual<T, U> = Equal<T, U> extends true ? false : true;
type Dist<T> = T extends T ? [T] : never;
type IsUnion<T> = NotEqual<[T], Dist<T>>;
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true
type IsUnion<T> = UnionToTuple<T>['length'] extends 1 ? false : true;

#IsTuple

type IsTuple<T> = T extends readonly [infer T, ...infer Rest] ? IsTuple<Rest> : Equal<T, []>;
type IsTuple<T> = T extends readonly unknown[]
  ? number extends T['length'] ? false : true : false;

IsTuple<never> never has some strange behavior. [T] extends [never]

#Union to Intersection

type Dist<T> = T extends T ? (x: T) => void : never;
type UnionToIntersection<U> =
  Dist<U> extends (x: infer X) => void ? X : never;
// X|Y
// Dist<X|Y> = (x: X) => void | (x: Y) => void;
// UnionToIntersection<X|Y> = X&Y
  • naked vs boxed type
  • covariance vs contravariance

#IsAny

type IsAny<T> = Equal<any, T>;

#Union to Tuple

type Dist<T> = T extends T ? (x: T) => void : never;
type UnionToIntersection<U> =
  Dist<U> extends (x: infer X) => void ? X : never;
// X|Y
// Dist<X|Y> = (x: X) => void | (x: Y) => void;
// UnionToIntersection<X|Y> = X&Y
type LastInUnion<U> =
  UnionToIntersection<Dist<U>> extends (x: infer L) => void
  ? L
  : never;
// Dist<X|Y> = (x: X) => void | (x: Y) => void;
// UnionToIntersection<Dist<X|Y>> = (x: X) => void & (x: Y) => void
// LastInUnion<X|Y> = ?
type UnionToTuple<U, Last = LastInUnion<U>> = [U] extends [never]
  ? []
  : [...UnionToTuple<Exclude<U, Last>>, Last];

#Intersection

type ToUnion<T> = T extends unknown[] ? T[number] : T;
type Intersection<T> = T extends [infer F]
  ? ToUnion<F>
  : T extends [infer F, ...infer Rest]
    ? ToUnion<F> & Intersection<Rest>
    : never;

#Sum

type ToString<T> = T extends number ? `${T}` : T;
type TupleOfLength<T extends string|number|bigint, Result extends unknown[] = []> =
  `${Result['length']}` extends `${T}` ? Result : TupleOfLength<T, [...Result, 0]>;

type Sum<A extends string | number | bigint, B extends string | number | bigint> = ToString<[...TupleOfLength<A>, ...TupleOfLength<B>]['length']>;

#TODO:

#Multiply

TODO:

repeat by sum

#Tag

TODO:

#Inclusive Range

TODO:

#Sort

TODO:

#DistributeUnions

TODO:

#Assert Array Index

TODO:


EOF