/*! * ======================================================================== * @rzl-zone/ts-types-plus * ------------------------------------------------------------------------ * Version: `0.1.9` * Author: `Rizalvin Dwiky ` * Repository: `https://github.com/rzl-zone/rzl-zone/tree/main/packages/ts-types-plus` * ======================================================================== */ /** ------------------------------------------------------- * * ***Utility Type: `If`.*** * ------------------------------------------------------- * - **Conditional:** * - Returns the second argument if the first argument is `true`, otherwise * returns the third argument. * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template Condition - The boolean condition to check. * @template IfTrue - The branch type if condition is `true`. (default: `true`). * @template IfFalse - The branch type if condition is `false`. (default: `false`). * @example * ```ts * type A = If; * // ➔ "valid" * type B = If; * // ➔ "invalid" * ``` */ type If = Condition extends true ? IfTrue : IfFalse; /** ------------------------------------------------------- * * ***Utility Type: `IsNever`.*** * ------------------------------------------------------- * ****Conditional**: returns `true` if `T` is `never`, otherwise `false`.** * @template T - Type to check. * @example * ```ts * type A = IsNever; // ➔ true * type B = IsNever; // ➔ false * ``` */ type IsNever = [T] extends [never] ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `IfNever`.*** * ------------------------------------------------------- * **Conditional**: Selects one of two branches depending on whether `T` is `never`.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - Type to check. * @template IfTrue - The branch type if `T` is `never`, (default: `true`). * @template IfFalse - The branch type if `T` is not `never`, (default: `false`). * @example * ```ts * type A = IfNever; * // ➔ true * type B = IfNever; * // ➔ false * type C = IfNever; * // ➔ 'valid' * type D = IfNever; * // ➔ 'no' * ``` */ type IfNever = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `NeverifyPropertiesOptions`.*** * ------------------------------------------------------- * **Configuration options for the ***{@link NeverifyProperties | `NeverifyProperties`}*** type utility.** * @example * ```ts * type Opt1 = NeverifyPropertiesOptions; * // ➔ { makeOptional: boolean } * ``` */ type NeverifyPropertiesOptions = { /** * ***Whether to make all properties optional, defaultValue: `false`.*** * * @default false */ makeOptional: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `NeverifyProperties`.*** * ------------------------------------------------------- * **Turns all properties of an object to type `never`.** * - If `Options["makeOptional"]` is `true`, properties will be optional. * @template T - Object type to transform. * @template Options - Configuration options (default: `{ makeOptional: false }`). * @example * ```ts * type A = NeverifyProperties<{ a: string; b: string }>; * // ➔ { a: never; b: never } * type B = NeverifyProperties<{ a: string; b: string }, { makeOptional: true }>; * // ➔ { a?: never; b?: never } * ``` */ type NeverifyProperties = { [K in keyof T]: never } extends infer Result ? If, Result> : never; /** ------------------------------------------------------- * * ***Utility Type: `Arrayable`.*** * ------------------------------------------------------- * **Useful when a function or API accepts **either one item or multiple items**.** * - **Represents a type that can be either:** * - a single value of type `T`, or an array of values of type `T`. * @template T - The element type. * @example * ```ts * function toArray(input: Arrayable): T[] { * return Array.isArray(input) ? input : [input]; * } * * type A = Arrayable; * // ➔ string | string[] * * const a: A = "foo"; * const b: A = ["foo", "bar"]; * ``` */ type Arrayable = T | Array; /** ------------------------------------------------------- * * ***Utility Type: `MutableArray`.*** * ------------------------------------------------------- * **Recursively creates a **mutable version** of a readonly array, tuple, or object type.** * @description * By default, TypeScript infers tuple/array literals as `readonly` (especially with `as const`). * This utility removes the `readonly` modifier from all elements recursively, * turning a readonly tuple, array, or object into a mutable one. * - **Behavior:** * - Optionally, if `Widen` is `true`, literal types (`1`, `'foo'`, `true`) are widened to * their primitive equivalents (`number`, `string`, `boolean`) for easier assignment. * @template T - The readonly array, tuple, or object type to make mutable. * @template Widen - Whether to widen literal primitive types to their base types (default: `false`). * @example * ```ts * type A = readonly [1, 2, 3]; * type B = MutableArray; * // ➔ [1, 2, 3] * * const x: A = [1, 2, 3] as const; * // x[0] = 9; // ❌ Error: read-only * * const y: MutableArray = [1, 2, 3]; * y[0] = 9; // ✅ Allowed * * // Recursive example with objects * type Obj = readonly [{ a: 1, b: readonly [2] }]; * type MutableObj = MutableArray; * // ➔ [{ a: number; b: [number]; }] * ``` */ type MutableArray = T extends ((...args: any) => any) ? T : T extends readonly any[] ? { -readonly [K in keyof T]: MutableArray } : T extends object ? { -readonly [K in keyof T]: MutableArray } : Widen extends true ? T extends number ? number : T extends string ? string : T extends boolean ? boolean : T extends bigint ? bigint : T extends symbol ? symbol : T : T; /** -------------------------------------------------- * * ***Utility Type: `GetArrayElementType`.*** * -------------------------------------------------- * **Gets the element type from a readonly array or tuple.** * - ✅ Useful when working with `as const` arrays to extract the union of literal types. * @template T - A readonly array or tuple type. * @example * ```ts * const roles = ['admin', 'user'] as const; * type Role = GetArrayElementType; * // ➔ "admin" | "user" * ``` */ type GetArrayElementType = T extends readonly (infer U)[] ? U : never; /** ------------------------------------------------------- * * ***Utility Type: `EmptyArray`.*** * ------------------------------------------------------- * **A type-level utility that returns `T` if it is an ***empty array***, * otherwise returns `never`.** * @template T - The array type to check. * @example * ```ts * type A = EmptyArray<[]>; * // ➔ [] * type B = EmptyArray<[1]>; * // ➔ never * type C = EmptyArray; * // ➔ string[] * type D = EmptyArray; * // ➔ number[] * type E = EmptyArray; * // ➔ readonly [] * ``` */ type EmptyArray = T extends readonly [unknown, ...unknown[]] ? never : T; /** ------------------------------------------------------- * * ***Utility Type: `NonEmptyArray`.*** * ------------------------------------------------------- * **A type-level utility that returns `T` if it is a ***non-empty array***, * otherwise returns `never`.** * @template T - The array type to check. * @example * ```ts * type A = NonEmptyArray<[]>; * // ➔ never * type B = NonEmptyArray<[1]>; * // ➔ [1] * type C = NonEmptyArray; * // ➔ never * type D = NonEmptyArray; * // ➔ never * type E = NonEmptyArray; * // ➔ never * ``` */ type NonEmptyArray = If>, T, never>; /** ------------------------------------------------------- * * ***Utility Type: `IsEmptyArray`.*** * ------------------------------------------------------- * **A type-level utility that evaluates to `true` if `T` is an ***empty array.*** * (or can be empty per this definition), otherwise `false`.** * @template T - The array type to check. * @example * ```ts * type A = IsEmptyArray<[]>; * // ➔ true * type B = IsEmptyArray<[1]>; * // ➔ false * type C = IsEmptyArray; * // ➔ true * type D = IsEmptyArray; * // ➔ true * type E = IsEmptyArray; * // ➔ true * ``` */ type IsEmptyArray = If>, false, true>; /** ------------------------------------------------------- * * ***Utility Type: `IsNonEmptyArray`.*** * ------------------------------------------------------- * **A type-level utility that evaluates to `true` if `T` is a ***non-empty array.*** * (strictly a non-empty tuple), otherwise `false`.** * @template T - The array type to check. * @example * ```ts * type A = IsNonEmptyArray<[]>; * // ➔ false * type B = IsNonEmptyArray<[1]>; * // ➔ true * type C = IsNonEmptyArray; * // ➔ false * type D = IsNonEmptyArray; * // ➔ false * type E = IsNonEmptyArray; * // ➔ false * ``` */ type IsNonEmptyArray = If>, true, false>; /** ------------------------------------------------------- * * ***Utility Type: `IfEmptyArray`.*** * ------------------------------------------------------- * **Returns the second argument if `T` is an ***empty array*** (per this utility), * otherwise returns the third argument.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - The array type to check. * @template IfTrue - Returned type if `T` is empty by this definition. * @template IfFalse - Returned type if `T` is not empty by this definition. * @example * ```ts * type A = IfEmptyArray<[]>; * // ➔ true * type B = IfEmptyArray<[1]>; * // ➔ false * type C = IfEmptyArray; * // ➔ true * type D = IfEmptyArray; * // ➔ true * type E = IfEmptyArray<[], "yes", "no">; * // ➔ "yes" * type F = IfEmptyArray<[1], "yes", "no">; * // ➔ "no" * type G = IfEmptyArray; * // ➔ "yes" * ``` */ type IfEmptyArray = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfNonEmptyArray`.*** * ------------------------------------------------------- * **Returns the second argument if `T` is a ***non-empty array*** (strict tuple), * otherwise returns the third argument.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - The array type to check. * @template IfTrue - Returned type if `T` is non-empty by this definition. * @template IfFalse - Returned type if `T` is not non-empty by this definition. * @example * ```ts * type A = IfNonEmptyArray<[]>; * // ➔ false * type B = IfNonEmptyArray<[1]>; * // ➔ true * type C = IfNonEmptyArray; * // ➔ false * type D = IfNonEmptyArray; * // ➔ false * type E = IfNonEmptyArray<[1], "yes", "no">; * // ➔ "yes" * type F = IfNonEmptyArray<[], "yes", "no">; * // ➔ "no" * type G = IfNonEmptyArray; * // ➔ "no" * ``` */ type IfNonEmptyArray = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `Not`.*** * ------------------------------------------------------- * **Accepts a boolean type `T` and returns its negation.** * @template T - Boolean type to negate. * @example * ```ts * type A = Not; // ➔ false * type B = Not; // ➔ true * ``` */ type Not = T extends true ? false : true; /** --------------------------------------------------------------------------- * * ***Options for {@link Pop|`Pop`}.*** * --------------------------------------------------------------------------- * **Configuration options for the {@link Pop | **`Pop`**} type utility.** */ type PopOptions = { /** * If `true`, {@link Pop | **`Pop`**} will return a tuple `[Rest, Removed]` * instead of just the remaining array, default: `false`. * * @example * ```ts * type Options = { includeRemoved: true }; * type Result = Pop<[1, 2, 3], Options>; // ➔ [[1, 2], 3] * ``` */ includeRemoved: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `Pop`.*** * ------------------------------------------------------- * **Removes the last element from a tuple/array type.** * - If the `includeRemoved` option is `true`, it returns a tuple `[Rest, Removed]` * where `Rest` is the array without the last element, and `Removed` is the last * element. * @template T - The tuple or array to pop from. * @template Options - Configuration object. Default `{ includeRemoved: false }`. * @example * ```ts * // Removes last element * type Case1 = Pop<[1, 2, 3]> * // ➔ [1, 2] * * // Removes last element and includes the removed value * type Case2 = Pop<[1, 2, 3], { includeRemoved: true }> * // ➔ [[1, 2], 3] * * // Edge case: empty array * type Case3 = Pop<[]> * // ➔ never * ``` */ type Pop = IsEmptyArray extends true ? never : T extends readonly [...infer Rest extends readonly unknown[], infer Removed] ? If : never; /** ------------------------------------------------------- * * ***Utility Type: `Extends`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether the first argument ***extends*** the second argument.** * @template T - The type to check. * @template Base - The type to compare against. * @example * ```ts * type A = Extends<1, number>; // ➔ true * type B = Extends; // ➔ false * ``` */ type Extends = [T] extends [Base] ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `NotExtends`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether the first argument does ***not extend*** the second argument.** * @template T - The type to check. * @template Base - The type to compare against. * @example * ```ts * type A = NotExtends<1, number>; // ➔ false * type B = NotExtends; // ➔ true * ``` */ type NotExtends = Not>; /** ------------------------------------------------------- * * ***Utility Type: `IfExtends`.*** * ------------------------------------------------------- * - **Conditional:** * - Returns the third argument if the first argument ***extends*** the second * argument, otherwise returns the fourth argument. * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - The type to check. * @template Base - The type to compare against. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfExtends<1, number, "valid">; * // ➔ "valid" * type B = IfExtends<1, string, "valid", "invalid">; * // ➔ "invalid" * ``` */ type IfExtends = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfNotExtends`.*** * ------------------------------------------------------- * - **Conditional:** * - Returns the third argument if the first argument does ***not extend*** the * second argument, otherwise returns the fourth argument. * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - The type to check. * @template Base - The type to compare against. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfNotExtends<1, string, "valid">; * // ➔ "valid" * type B = IfNotExtends<1, number, "valid", "invalid">; * // ➔ "invalid" * ``` */ type IfNotExtends = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `ExtendsArr`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether every element of the first array argument ***extends*** the second argument.** * @template T - The array to check. * @template Base - The type to compare each element against. * @example * ```ts * type A = ExtendsArr<[1, 2, 3], number>; * // ➔ true * type B = ExtendsArr<[1, "2", 3], number>; * // ➔ false * ``` */ type ExtendsArr = IsEmptyArray extends true ? true : Pop extends readonly [infer Rest extends readonly unknown[], infer Removed] ? Extends extends true ? ExtendsArr : false : false; /** ------------------------------------------------------- * * ***Utility Type: `And`.*** * ------------------------------------------------------- * **Performs a **logical AND** operation between two boolean types.** * - **Behavior:** * - Returns `true` if **both** conditions extend `true`. * - Returns `false` for otherwise. * @template Condition1 - The first condition. * @template Condition2 - The second condition. * @example * ```ts * type Case1 = And; * // ➔ true * type Case2 = And; * // ➔ false * type Case3 = And; * // ➔ false * type Case4 = And; * // ➔ false * ``` */ type And = IfExtends>; /** ------------------------------------------------------- * * ***Utility Type: `AndArr`.*** * ------------------------------------------------------- * **Performs a **logical AND** operation across all elements in an array of * boolean types.** * - **Behavior:** * - Returns `true` if **all elements** extend `true`. * - Returns `false` if **any element** is not `true`. * @template Conditions - A readonly array of boolean conditions. * @example * ```ts * type Case1 = AndArr<[true, true, true]>; * // ➔ true * type Case2 = AndArr<[true, true, false]>; * // ➔ false * type Case3 = AndArr<[false, false, false]>; * // ➔ false * type Case4 = AndArr<[]>; * // ➔ false * ``` */ type AndArr = Extends<[], Conditions> extends true ? false : Extends; /** ------------------------------------------------------- * * ***Utility Type: `IsStringLiteral`.*** * ------------------------------------------------------- * **Returns a boolean whether the passed argument is literal string.** * @template T - The type value to check. * @example * type Case1 = IsStringLiteral<'a'>; // ➔ true * type Case2 = IsStringLiteral<1>; // ➔ false * type Case3 = IsStringLiteral; // ➔ false */ type IsStringLiteral = If, Extends extends true ? false : true>; /** ------------------------------------------------------- * * ***Utility Type: `IfNot`.*** * ------------------------------------------------------- * - **Conditional:** * - Returns the second argument if the first argument is `false`, otherwise returns the third argument. * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template Condition - The boolean condition to check. * @template IfTrue - The branch type if condition is `false`. (default: `true`). * @template IfFalse - The branch type if condition is `true`. (default: `false`). * @example * ```ts * type A = IfNot; * // ➔ "valid" * type B = IfNot; * // ➔ "invalid" * ``` */ type IfNot = If; /** ------------------------------------------------------- * * ***Utility Type: `WordSeparator`.*** * ------------------------------------------------------- * **A type-level utility that defines all valid ***word separators***.** * - Can be a space `" "`, a dash `"-"`, or an underscore `"_"`. * @example * type A = WordSeparator; // ➔ " " | "-" | "_" */ type WordSeparator = " " | "-" | "_"; /** -------------------------------------------------- * * ***Utility Type: `Whitespace`.*** * -------------------------------------------------- * **Represents common whitespace characters.** * - ✅ Used as the default trimming characters in string utility types. * @example * type W = Whitespace; // ➔ " " | "\t" | "\r" | "\n" */ type Whitespace = " " | "\t" | "\r" | "\n"; /** * **Helper Type Internal.** */ type SafeKeyTrimming = Exclude; /** -------------------------------------------------- * * ***Utility Type: `TrimLeft`.*** * -------------------------------------------------- * **Recursively trims specified characters (default: **{@link Whitespace | `Whitespace`}**) from the **start (left)** of a string.** * @template Text - The string to trim. * @template Chars - The characters to remove (default: `Whitespace`). * @example * type T1 = TrimLeft<"\n hello", " " | "\n">; * // ➔ "hello" * type T2 = TrimLeft<" world">; * // ➔ "world" * type T3 = TrimLeft<" world ">; * // ➔ "world " */ type TrimLeft = Text extends `${SafeKeyTrimming}${infer Rest}` ? TrimLeft : Text; /** -------------------------------------------------- * * ***Utility Type: `TrimRight`.*** * -------------------------------------------------- * **Recursively trims specified characters (default: **{@link Whitespace | `Whitespace`}**) from the **end (right)** of a string.** * @template Text - The string to trim. * @template Chars - The characters to remove (default: `Whitespace`). * @example * type T1 = TrimRight<"hello \t", " " | "\t">; * // ➔ "hello" * type T2 = TrimRight<"world ">; * // ➔ "world" * type T2 = TrimRight<" world ">; * // ➔ " world" */ type TrimRight = Text extends `${infer Rest}${SafeKeyTrimming}` ? TrimRight : Text; /** -------------------------------------------------- * * ***Utility Type: `Trim`.*** * -------------------------------------------------- * **Trims specified characters (default: **{@link Whitespace | `Whitespace`}**) * from **both the start and end** of a string.** * @template Chars - The characters to remove (default: `Whitespace`). * @example * type T1 = Trim<" hello ", " ">; * // ➔ "hello" * type T2 = Trim<"\n world \t">; * // ➔ "world" */ type Trim = TrimRight, Chars>; /** ------------------------------------------------------- * * ***Utility Type: `TrimsLower`.*** * ------------------------------------------------------- * **Trims leading & trailing whitespace from a string and * converts it to **lowercase**.** * @description * Utilizes **{@link Trim | `Trim`}** to remove whitespace and * **{@link Lowercase | `Lowercase`}** to convert the string to lowercase. * @template S - The input string to transform. * @example * ```ts * type T1 = TrimsLower<" HeLLo \n">; * // ➔ "hello" * type T2 = TrimsLower<" WoRLD ">; * // ➔ "world" * ``` */ type TrimsLower = Lowercase>; /** ------------------------------------------------------- * * ***Utility Type: `TrimsUpper`.*** * ------------------------------------------------------- * **Trims leading & trailing whitespace from a string and * converts it to **uppercase**.** * @description * Utilizes **{@link Trim | `Trim`}** to remove whitespace and * **{@link Uppercase | `Uppercase`}** to convert the string to uppercase. * @template S - The input string to transform. * @example * ```ts * type T1 = TrimsUpper<" HeLLo \n">; * // ➔ "HELLO" * type T2 = TrimsUpper<" WoRLD ">; * // ➔ "WORLD" * ``` */ type TrimsUpper = Uppercase>; /** ------------------------------------------------------- * * ***Utility Type: `AnyString`.*** * ------------------------------------------------------- * **A utility type that represents **any string value** while * preventing unwanted widening of string literals to `string`.** * @description * This is achieved by intersecting `string` with `{}`, * ensuring that the type remains assignable to `string` * but is treated as a unique type in generic constraints. * - **Useful in scenarios where:** * - You want to accept **any string**, but still preserve * literal types in inference. * - You need stricter typing than just `string`. * @example * ```ts * declare function acceptsAnyString(value: T): T; * * // Preserves literal * const a = acceptsAnyString("hello"); * // ➔ "hello" * * // Also allows generic string * const b = acceptsAnyString(String("world")); * // ➔ string * ``` */ type AnyString = {} & string; /** ------------------------------------------------------- * * ***Utility Type: `EmptyString`.*** * ------------------------------------------------------- * - **Conditional type:** * - Returns the type `T` only if it is the empty string `""`. * - Optionally trims whitespace before checking. * - **Behavior:** * - If `WithTrim` is `true` (default), trims `T` before checking. * - If `T` is the general `string` type, returns `never`. * - If `T` is empty (after optional trimming), returns `T` or `Trim`. * @template T - The string type to check. * @template WithTrim - Whether to trim whitespace before checking (default `true`). * @example * ```ts * // Basic empty string * type Case1 = EmptyString<"">; * // ➔ "" * * // Non-empty string * type Case2 = EmptyString<"abc">; * // ➔ never * * // General string type * type Case3 = EmptyString; * // ➔ never * * // With leading/trailing whitespace * type Case4 = EmptyString<" ", true>; * // ➔ "" (trimmed) * type Case5 = EmptyString<" ", false>; * // ➔ never (not trimmed) * ``` */ type EmptyString = "" extends (WithTrim extends true ? Trim : T) ? string extends (WithTrim extends true ? Trim : T) ? never : WithTrim extends true ? Trim : T : never; /** ------------------------------------------------------- * * ***Utility Type: `NonEmptyString`.*** * ------------------------------------------------------- * - **Conditional type:** * - Returns the type `T` only if it is a non-empty string. * - Optionally trims whitespace before checking. * - **Behavior:** * - If `WithTrim` is `true` (default), trims `T` before checking. * - If `T` is the general `string` type, returns `string`. * - If `T` is empty (after optional trimming), returns `never`. * @template T - The string type to check. * @template WithTrim - Whether to trim whitespace before checking (default `true`). * @example * ```ts * // Non-empty string * type Case1 = NonEmptyString<"abc">; // ➔ "abc" * * // Empty string * type Case2 = NonEmptyString<"">; // ➔ never * * // General string type * type Case3 = NonEmptyString; // ➔ string * * // String with whitespace * type Case4 = NonEmptyString<" ", true>; // ➔ never (trimmed to empty) * type Case5 = NonEmptyString<" ", false>; // ➔ " " (not trimmed) * ``` */ type NonEmptyString = string extends T ? string : If>, WithTrim extends true ? Trim : T, never>; /** ------------------------------------------------------- * * ***Utility Type: `IsEmptyString`.*** * ------------------------------------------------------- * - **Conditional type:** * - Returns `true` if `T` is exactly the empty string `""`. * - Optionally trims whitespace before checking. * - **Behavior:** * - If `WithTrim` is `true` (default), trims `T` before checking. * - If `T` is empty after optional trimming, returns `true`. * - Otherwise, returns `false`. * @template T - The string type to check. * @template WithTrim - Whether to trim whitespace before checking (default `true`). * @example * ```ts * type Case1 = IsEmptyString<"">; * // ➔ true * type Case2 = IsEmptyString<"abc">; * // ➔ false * type Case3 = IsEmptyString<" ", true>; * // ➔ true (trimmed) * type Case4 = IsEmptyString<" ", false>; * // ➔ false (not trimmed) * ``` */ type IsEmptyString = IfNot>>; /** ------------------------------------------------------- * * ***Utility Type: `IsNonEmptyString`.*** * ------------------------------------------------------- * - **Conditional type:** * - Returns `true` if `T` is a non-empty string. * - Optionally trims whitespace before checking. * - **Behavior:** * - If `WithTrim` is `true` (default), trims `T` before checking. * - Returns `true` if `T` is non-empty after optional trimming. * - Returns `false` if `T` is empty (after trimming if `WithTrim=true`). * @template T - The string type to check. * @template WithTrim - Whether to trim whitespace before checking (default `true`). * @example * ```ts * type Case1 = IsNonEmptyString<"abc">; * // ➔ true * type Case2 = IsNonEmptyString<"">; * // ➔ false * type Case3 = IsNonEmptyString<" ", true>; * // ➔ false (trimmed) * type Case4 = IsNonEmptyString<" ", false>; * // ➔ true (not trimmed) * ``` */ type IsNonEmptyString = IfNot>>; /** ------------------------------------------------------- * * ***Utility Type: `IfEmptyString`.*** * ------------------------------------------------------- * - **Conditional type:** * - Returns `IfTrue` if `T` is an empty string `""`, otherwise returns `IfFalse`. * - Optionally trims whitespace before checking. * @template T - The string type to check. * @template IfTrue - Type returned if `T` is empty (default `true`). * @template IfFalse - Type returned if `T` is not empty (default `false`). * @template WithTrim - Whether to trim whitespace before checking (default `true`). * @example * ```ts * type Case1 = IfEmptyString<"">; * // ➔ true * type Case2 = IfEmptyString<"abc">; * // ➔ false * type Case3 = IfEmptyString<"", "yes", "no">; * // ➔ "yes" * type Case4 = IfEmptyString<"abc", "yes", "no">; * // ➔ "no" * type Case5 = IfEmptyString<" ", "yes", "no", true>; * // ➔ "yes" (trimmed) * type Case6 = IfEmptyString<" ", "yes", "no", false>; * // ➔ "no" (not trimmed) * ``` */ type IfEmptyString = IfNot>, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfNonEmptyString`.*** * ------------------------------------------------------- * - **Conditional type:** * - Returns `IfTrue` if `T` is a non-empty string, otherwise returns `IfFalse`. * - Optionally trims whitespace before checking. * @template T - The string type to check. * @template IfTrue - Type returned if `T` is non-empty (default `true`). * @template IfFalse - Type returned if `T` is empty (default `false`). * @template WithTrim - Whether to trim whitespace before checking (default `true`). * @example * ```ts * type Case1 = IfNonEmptyString<"abc">; * // ➔ true * type Case2 = IfNonEmptyString<"">; * // ➔ false * type Case3 = IfNonEmptyString<"abc", "yes", "no">; * // ➔ "yes" * type Case4 = IfNonEmptyString<"", "yes", "no">; * // ➔ "no" * type Case5 = IfNonEmptyString<" ", "yes", "no", true>; * // ➔ "no" (trimmed) * type Case6 = IfNonEmptyString<" ", "yes", "no", false>; * // ➔ "yes" (not trimmed) * ``` */ type IfNonEmptyString = IfNot>, IfTrue, IfFalse>; /** @private ***types for {@link AreAnagrams}.*** * */ type _AreAnagrams = IsEmptyString extends true ? IsEmptyString extends true ? true : false : Str1 extends `${infer First extends string}${infer Rest1 extends string}` ? Str2 extends `${infer Prev extends string}${First}${infer Rest2 extends string}` ? _AreAnagrams : false : never; /** ------------------------------------------------------- * * ***Utility Type: `AreAnagrams`.*** * ------------------------------------------------------- * **Determines whether two string literal types are ***anagrams*** of each other.** * - **Behavior:** * - Returns `true` if both strings contain exactly the same characters in * any order. * - Returns `false` otherwise. * @template Str1 - The first string literal. * @template Str2 - The second string literal. * @example * ```ts * type Case1 = AreAnagrams<"name", "eman">; * // ➔ true * type Case2 = AreAnagrams<"name", "emand">; * // ➔ false * type Case3 = AreAnagrams<"abc", "cba">; * // ➔ true * type Case4 = AreAnagrams<"abc", "abcd">; * // ➔ false * ``` */ type AreAnagrams = And, IsStringLiteral> extends true ? _AreAnagrams : false; /** ------------------------------------------------------- * * ***Utility Type: `IsAny`.*** * ------------------------------------------------------- * **A type-level utility that checks whether a type is ***`any`***.** * - **Behavior:** * - Returns `true` if `T` is `any`. * - Returns `false` for otherwise. * @template T - The type to evaluate. * @example * ```ts * type A = IsAny; // ➔ true * type B = IsAny; // ➔ false * type C = IsAny; // ➔ false * type D = IsAny; // ➔ false * ``` */ type IsAny = 0 extends 1 & T ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `IfAny`.*** * ------------------------------------------------------- * **A type-level conditional utility that returns one type if ***`T` is `any`***, * and another type otherwise.** * - **Behavior:** * - Defaults to `true` when `T` is `any`. * - Defaults to `false` for otherwise. * @template T - The type to check. * @template IfTrue - The type to return if `T` is `any`, *(default: `true`)*. * @template IfFalse - The type to return if `T` is not `any`, *(default: `false`)*. * @example * ```ts * type A = IfAny; * // ➔ string * type B = IfAny; * // ➔ number * ``` */ type IfAny = If, IfTrue, IfFalse>; /** * ***Configuration options for a type-level utility for * {@link AnifyProperties | `AnifyProperties`}.*** */ type AnifyPropertiesOptions = { /** If `makeOptional: true`, all properties become optional, otherwise, all properties are required and typed as `any`, defaultValue: `false`. * * @default false */ makeOptional: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `AnifyProperties`.*** * ------------------------------------------------------- * **A type-level utility that transforms all properties of an object * into ***`any`***.** * - **Behavior:** * - If `makeOptional: true`, all properties become optional. * - Otherwise, all properties are required and typed as `any`. * @template T The object type to transform. * @template Options Configuration options, defaults to `{ makeOptional: false }`. * @example * ```ts * type A = AnifyProperties<{a: string; b: number}>; * // ➔ { a: any; b: any } * type B = AnifyProperties<{a: string; b: number}, { makeOptional: true }>; * // ➔ { a?: any; b?: any } * ``` */ type AnifyProperties = { [K in keyof T]: any } extends infer Result ? If, Result> : never; /** -------------------------------------------------- * * ***Utility Type: `AnyFunction`.*** * -------------------------------------------------- * **A generic type representing **any function** with * any arguments and any return type.** * @example * const fn: AnyFunction = (a, b) => a + b; * console.log(fn(1, 2)); // ➔ 3 * * const fn2: AnyFunction = (x, y, z) => x + y - z; * console.log(fn2(10, 20, 5)); // ➔ 25 */ type AnyFunction = (...args: any[]) => any; /** -------------------------------------------------- * * ***Utility Type: `ArgumentTypes`.*** * -------------------------------------------------- * **Extracts the **argument types** of a given function type `F`.** * - ✅ Useful when you need to infer or reuse the parameter types * from an existing function signature. * @template F - A function type from which to extract argument types. * @example * ```ts * type Args = ArgumentTypes<(a: number, b: string) => void>; * // ➔ [number, string] * ``` */ type ArgumentTypes = F extends ((...args: infer A) => any) ? A : never; /** ------------------------------------------------------- * * ***Utility Type: `ArrayElementType`.*** * ------------------------------------------------------- * **A type-level utility that extracts the element type of an array.** * - **Behavior:** * - Works with both mutable and readonly arrays. * - If `T` is not an array, resolves to `never`. * @template T - The array type to extract the element type from. * @example * ```ts * type A = ArrayElementType; * // ➔ string * type B = ArrayElementType; * // ➔ "a" | "b" * type C = ArrayElementType; * // ➔ never * ``` */ type ArrayElementType = T extends Readonly> ? Item : never; /** ------------------------------------------------------- * * ***Utility Type: `FixNeverArrayRecursive`.*** * ------------------------------------------------------- * **A type-level utility that **recursively transforms arrays of type `never[]` into empty arrays**.** * - **Behavior:** * - Preserves `readonly` modifiers. * - Applies recursively for nested arrays. * - Leaves other types unchanged. * @template T - The input type to recursively fix. * @example * ```ts * type A = FixNeverArrayRecursive; * // ➔ [] * type B = FixNeverArrayRecursive; * // ➔ readonly [] * type C = FixNeverArrayRecursive; * // ➔ string[] * type D = FixNeverArrayRecursive<(never | string)[]>; * // ➔ (never | string)[] * type E = FixNeverArrayRecursive<(never[])[]>; * // ➔ [][] * ``` */ type FixNeverArrayRecursive = T extends readonly never[] ? T extends never[] ? [] : readonly [] : T extends (infer U)[] ? FixNeverArrayRecursive[] : T extends readonly (infer U)[] ? readonly FixNeverArrayRecursive[] : T; /** ------------------------------------------------------- * * ***Utility Type: `NormalizeEmptyArraysRecursive`.*** * ------------------------------------------------------- * **A type-level utility that **recursively normalizes empty array types** by converting arrays whose element type is `never`, `null`, or `undefined` into empty tuple types (`[]`).** * - **Behavior:** * - Preserves `readonly` modifiers. * - Recurses into nested arrays. * - Leaves other array types unchanged. * @template T - The input type to normalize. * @example * ```ts * type A = NormalizeEmptyArraysRecursive; * // ➔ [] * type B = NormalizeEmptyArraysRecursive; * // ➔ readonly [] * type C = NormalizeEmptyArraysRecursive; * // ➔ [] * type D = NormalizeEmptyArraysRecursive<(null[] | string[])[]>; * // ➔ ([] | string[])[] * type E = NormalizeEmptyArraysRecursive; * // ➔ string[] * ``` */ type NormalizeEmptyArraysRecursive = T extends readonly (infer U)[] ? U extends never | null | undefined ? T extends readonly unknown[] ? T extends (infer _E)[] ? [] : readonly [] : never : T extends (infer _E)[] ? NormalizeEmptyArraysRecursive[] : readonly NormalizeEmptyArraysRecursive[] : T; /** ------------------------------------------------------- * * ***Utility Type: `RemoveEmptyArrayElements`.*** * ------------------------------------------------------- * **A type-level utility that **recursively removes empty array elements (`[]`) from a tuple type**.** * - **Behavior:** * - If `T` is a tuple, checks the first element: * - If `Head` is an empty array type (`[]`), it is removed. * - Otherwise, `Head` is preserved. * - Repeats recursively on the rest of the tuple. * - Leaves non-tuple types unchanged. * @template T - The tuple type to process. * @example * ```ts * type A = RemoveEmptyArrayElements<[[], 1, [], 2]>; * // ➔ [1, 2] * type B = RemoveEmptyArrayElements<[]>; * // ➔ [] * type C = RemoveEmptyArrayElements<[[], [], []]>; * // ➔ [] * type D = RemoveEmptyArrayElements<[1, 2, 3]>; * // ➔ [1, 2, 3] * ``` */ type RemoveEmptyArrayElements = T extends [infer Head, ...infer Tail] ? Head extends [] ? RemoveEmptyArrayElements : [Head, ...RemoveEmptyArrayElements] : T extends [] ? [] : T; /** --------------------------------------------------------------------------- * * ***Type Options for {@link LastCharacter | `LastCharacter`}.*** * --------------------------------------------------------------------------- */ type LastCharacterOptions = { includeRest: boolean; }; type _LastCharacter = string extends T ? string : T extends `${infer First}${infer Rest}` ? IsEmptyString extends true ? If : _LastCharacter : T; /** ------------------------------------------------------- * * ***Utility Type: `LastCharacter`.*** * ------------------------------------------------------- * **Accepts a string argument and returns its last character.** * - If the `includeRest` option is `true`, returns the last character and the rest of the string in the format: `[last, rest]`. * @template T - The string to get the last character from. * @template Options - Options to include the rest of the string. * @example * type Case1 = LastCharacter<'abc'>; * // ➔ 'c' * type Case2 = LastCharacter<'abc', { includeRest: true }>; * // ➔ ['c', 'ab'] */ type LastCharacter = IfExtends, _LastCharacter>; /** ------------------------------------------------------- * * ***Utility Type: `Or`.*** * ------------------------------------------------------- * **Computes the logical OR of two type-level boolean conditions.** * @template Condition1 - First boolean condition. * @template Condition2 - Second boolean condition. * @example * ```ts * type Case1 = Or; // ➔ true * type Case2 = Or; // ➔ true * type Case3 = Or; // ➔ false * type Case4 = Or; // ➔ true * ``` * @remarks * - Uses {@link IfExtends | **`IfExtends`**} to determine if either condition is `true`. * - Returns `true` if at least one of the two conditions is `true`. * - Returns `false` only if both are `false`. */ type Or = IfExtends>; /** ------------------------------------------------------- * * ***Utility Type: `OrArr`.*** * ------------------------------------------------------- * **Computes the logical OR of all elements inside a tuple or array of boolean types.** * @template Conditions - An array of boolean type elements. * @example * ```ts * type Case1 = OrArr<[true, true, true]>; // ➔ true * type Case2 = OrArr<[true, true, false]>; // ➔ true * type Case3 = OrArr<[false, false, false]>; // ➔ false * type Case4 = OrArr<[]>; // ➔ false * ``` * @remarks * - Uses TypeScript's indexed access types and conditional type inference. * - Returns `true` if at least one element in the array is `true`. * - Returns `false` if all elements are `false` or array is empty. */ type OrArr = true extends Conditions[number] ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `Push`.*** * ------------------------------------------------------- * **Appends a type `U` to the end of a tuple or readonly array type `T`.** * @template T - The tuple or readonly array type to append U. * @template U - The type of the element to push. * @example * ```ts * type Case1 = Push<[1, 2, 3, 4], 5>; * // ➔ [1, 2, 3, 4, 5] * * type Case2 = Push<["a", "b"], "c">; * // ➔ ["a", "b", "c"] * ``` */ type Push = [...T, U]; type _Repeat = Iteration["length"] extends Count ? Result : _Repeat>; /** ------------------------------------------------------- * * ***Utility Type: `Repeat`.*** * ------------------------------------------------------- * **Repeats a string literal type `T` a specified number of times `Count`.** * - **Behavior:** * - Supports a range of `[0, 999]` due to TypeScript recursion limits. * - If `Count > 999`, it is automatically to `any` because error `Type instantiation is excessively deep and possibly infinite.ts(2589)`. * @template T - The string literal to repeat. * @template Count - Number of times to repeat. * @example * ```ts * type Case0 = Repeat<'x', 0>; // ➔ '' * type Case1 = Repeat<'x', 1>; // ➔ 'x' * type Case2 = Repeat<'x', 5>; // ➔ 'xxxxx' * type Case3 = Repeat<'ab', 3>; // ➔ 'ababab' * * // ❌ Invalid: * type Case1000 = Repeat<'x', 1000>; * // ➔ same as any (because: TypeScript recursion limits) * ``` */ type Repeat = _Repeat; /** ------------------------------------------------------- * * ***Utility Type: `OddDigit`.*** * ------------------------------------------------------- * **A union of string literal digits considered ***odd***.** * - Includes: `"1" | "3" | "5" | "7" | "9"`. * @example * ```ts * type A = OddDigit; // ➔ "1" | "3" | "5" | "7" | "9" * ``` */ type OddDigit = "1" | "3" | "5" | "7" | "9"; /** ------------------------------------------------------- * * ***Utility Type: `EvenDigit`.*** * ------------------------------------------------------- * **A union of string literal digits considered ***even***.** * - Includes: `"0" | "2" | "4" | "6" | "8"`. * @example * ```ts * type A = EvenDigit; // ➔ "0" | "2" | "4" | "6" | "8" * ``` */ type EvenDigit = "0" | "2" | "4" | "6" | "8"; /** ------------------------------------------------------- * * ***Utility Type: `Integer`.*** * ------------------------------------------------------- * **A type-level utility that validates if `T` is an ***integer***.** * - **Behavior:** * - Returns `T` if it is an integer. * - Returns `never` if `T` is a ***float*** (decimal). * @template T - A number type to validate. * @example * ```ts * type A = Integer<42>; // ➔ 42 * type B = Integer<-10>; // ➔ -10 * type C = Integer<3.14>; // ➔ never * ``` */ type Integer = `${T}` extends `${string}.${string}` ? never : T; /** ------------------------------------------------------- * * ***Utility Type: `Float`.*** * ------------------------------------------------------- * **A type-level utility that validates if `T` is a ***float***.** * - **Behavior:** * - Returns `T` if it is a float. * - Returns `never` if `T` is an ***integer***. * @template T - A number type to validate. * @example * ```ts * type A = Float<3.14>; // ➔ 3.14 * type B = Float<42>; // ➔ never * ``` */ type Float = If>, T, never>; /** ------------------------------------------------------- * * ***Utility Type: `Negative`.*** * ------------------------------------------------------- * **Extracts `T` if it is ***negative***, otherwise `never`.** * @template T - A number type to check. * @example * ```ts * type A = Negative<-10>; // ➔ -10 * type B = Negative<5>; // ➔ never * type C = Negative<0>; // ➔ never * ``` */ type Negative = `${T}` extends `-${string}` ? T : never; /** ------------------------------------------------------- * * ***Utility Type: `Positive`.*** * ------------------------------------------------------- * **Extracts `T` if it is ***positive*** (or zero), otherwise `never`.** * @template T - A number type to check. * @example * ```ts * type A = Positive<10>; // ➔ 10 * type B = Positive<0>; // ➔ 0 * type C = Positive<-5>; // ➔ never * ``` */ type Positive = If>, T, never>; /** ------------------------------------------------------- * * ***Utility Type: `PositiveInteger`.*** * ------------------------------------------------------- * **Restricts `T` to ***positive integers*** only.** * @template T - A number type. * @example * ```ts * type A = PositiveInteger<42>; // ➔ 42 * type B = PositiveInteger<0>; // ➔ 0 * type C = PositiveInteger<-5>; // ➔ never * type D = PositiveInteger<3.14>; // ➔ never * ``` */ type PositiveInteger = Positive>; /** ------------------------------------------------------- * * ***Utility Type: `NegativeInteger`.*** * ------------------------------------------------------- * **Restricts `T` to ***negative integers*** only.** * @template T - A number type. * @example * ```ts * type A = NegativeInteger<-42>; // ➔ -42 * type B = NegativeInteger<5>; // ➔ never * type C = NegativeInteger<-3.14>; // ➔ never * ``` */ type NegativeInteger = Negative>; /** ------------------------------------------------------- * * ***Utility Type: `PositiveFloat`.*** * ------------------------------------------------------- * **Restricts `T` to ***positive floats*** only.** * @template T - A number type. * @example * ```ts * type A = PositiveFloat<3.14>; // ➔ 3.14 * type B = PositiveFloat<-2.5>; // ➔ never * type C = PositiveFloat<5>; // ➔ never * ``` */ type PositiveFloat = Positive>; /** ------------------------------------------------------- * * ***Utility Type: `NegativeFloat`.*** * ------------------------------------------------------- * **Restricts `T` to ***negative floats*** only.** * @template T - A number type. * @example * ```ts * type A = NegativeFloat<-3.14>; // ➔ -3.14 * type B = NegativeFloat<2.5>; // ➔ never * type C = NegativeFloat<-5>; // ➔ never * ``` */ type NegativeFloat = Negative>; /** ------------------------------------------------------- * * ***Utility Type: `Even`.*** * ------------------------------------------------------- * **A type-level utility that extracts `T` if it is an ***even integer***.** * @template T - A number type to check. * @example * ```ts * type A = Even<0>; // ➔ 0 * type B = Even<4>; // ➔ 4 * type C = Even<5>; // ➔ never * type D = Even<24>; // ➔ 24 * type E = Even<27>; // ➔ never * type F = Even<3.14>; // ➔ never * ``` */ type Even = IfNot>, `${T}` extends `${string}${EvenDigit}` ? T : never, never>; /** ------------------------------------------------------- * * ***Utility Type: `Odd`.*** * ------------------------------------------------------- * **A type-level utility that extracts `T` if it is an ***odd integer***.** * @template T - A number type to check. * @example * ```ts * type A = Odd<0>; // ➔ never * type B = Odd<5>; // ➔ 5 * type C = Odd<4>; // ➔ never * type D = Odd<23>; // ➔ 23 * type E = Odd<26>; // ➔ never * type F = Odd<4.2>; // ➔ never * ``` */ type Odd = IfNot>, If>, T, never>, never>; /** ------------------------------------------------------- * * ***Utility Type: `IsInteger`.*** * ------------------------------------------------------- * **Whether `T` is an ***integer***.** * @example * ```ts * type A = IsInteger<-2>; // ➔ true * type B = IsInteger<0>; // ➔ true * type C = IsInteger<42>; // ➔ true * type D = IsInteger<3.14>; // ➔ false * ``` */ type IsInteger = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsFloat`.*** * ------------------------------------------------------- * **Whether `T` is a ***float***.** * @example * ```ts * type A = IsFloat<3.14>; // ➔ true * type B = IsFloat<-3.14>; // ➔ true * type C = IsFloat<0>; // ➔ false * type D = IsFloat<42>; // ➔ false * type E = IsFloat<-42>; // ➔ false * ``` */ type IsFloat = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsEven`.*** * ------------------------------------------------------- * **Whether `T` is ***even***.** * @example * ```ts * type A = IsEven<0>; // ➔ true * type B = IsEven<4>; // ➔ true * type C = IsEven<5>; // ➔ false * type D = IsEven<24>; // ➔ true * type E = IsEven<27>; // ➔ false * type F = IsEven<3.14>; // ➔ false * ``` */ type IsEven = If, `${T}` extends `${string}${EvenDigit}` ? true : false>; /** ------------------------------------------------------- * * ***Utility Type: `IsOdd`.*** * ------------------------------------------------------- * **Whether `T` is ***odd***.** * @example * ```ts * type A = IsEven<0>; // ➔ false * type B = IsEven<4>; // ➔ false * type C = IsEven<5>; // ➔ true * type D = IsEven<24>; // ➔ false * type E = IsEven<27>; // ➔ true * type F = IsEven<3.14>; // ➔ true * ``` */ type IsOdd = If, Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsPositive`.*** * ------------------------------------------------------- * **Whether `T` is ***positive***.** * @example * ```ts * type A = IsPositive<10>; // ➔ true * type B = IsPositive<0>; // ➔ true * type C = IsPositive<-5>; // ➔ false * type D = IsPositive<3.5>; // ➔ true * type E = IsPositive<-3.5>; // ➔ false * ``` */ type IsPositive = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsNegative`.*** * ------------------------------------------------------- * **Whether `T` is ***negative***.** * @example * ```ts * type A = IsNegative<-10>; // ➔ true * type B = IsNegative<5>; // ➔ false * type C = IsNegative<0>; // ➔ false * type D = IsPositive<3.5>; // ➔ false * type E = IsPositive<-3.5>; // ➔ true * ``` */ type IsNegative = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsPositiveInteger`.*** * ------------------------------------------------------- * **Whether `T` is a ***positive integer***.** * @example * ```ts * type A = IsPositiveInteger<42>; // ➔ true * type B = IsPositiveInteger<0>; // ➔ true * type C = IsPositiveInteger<-5>; // ➔ false * type D = IsPositiveInteger<3.14>; // ➔ false * ``` */ type IsPositiveInteger = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsNegativeInteger`.*** * ------------------------------------------------------- * **Whether `T` is a ***negative integer***.** * @example * ```ts * type A = IsNegativeInteger<-42>; // ➔ true * type B = IsNegativeInteger<5>; // ➔ false * type C = IsNegativeInteger<-3.14>; // ➔ false * ``` */ type IsNegativeInteger = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsPositiveFloat`.*** * ------------------------------------------------------- * **Whether `T` is a ***positive float***.** * @example * ```ts * type A = IsPositiveFloat<3.14>; // ➔ true * type B = IsPositiveFloat<-2.5>; // ➔ false * type C = IsPositiveFloat<5>; // ➔ false * ``` */ type IsPositiveFloat = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IsNegativeFloat`.*** * ------------------------------------------------------- * **Whether `T` is a ***negative float***.** * @example * ```ts * type A = IsNegativeFloat<-3.14>; // ➔ true * type B = IsNegativeFloat<2.5>; // ➔ false * type C = IsNegativeFloat<-5>; // ➔ false * ``` */ type IsNegativeFloat = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IfInteger`.*** * ------------------------------------------------------- * **Conditional: `If` branch if `T` is an ***integer***.** * @example * ```ts * type A = IfInteger<42>; // ➔ true * type B = IfInteger<3.14>; // ➔ false * type C = IfInteger<42, "yes", "no">; // ➔ "yes" * type D = IfInteger<3.14, "yes", "no">; // ➔ "no" * ``` */ type IfInteger = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfFloat`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is a ***float***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfFloat<3.14>; // ➔ true * type B = IfFloat<42>; // ➔ false * type C = IfFloat<3.14, "yes", "no">; // ➔ "yes" * type D = IfFloat<42, "yes", "no">; // ➔ "no" * ``` */ type IfFloat = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfEven`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is ***even***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfEven<4>; // ➔ true * type B = IfEven<5>; // ➔ false * type C = IfEven<4, "even", "odd">; // ➔ "even" * type D = IfEven<5, "even", "odd">; // ➔ "odd" * ``` */ type IfEven = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfOdd`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is ***odd***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfOdd<5>; // ➔ true * type B = IfOdd<4>; // ➔ false * type C = IfOdd<5, "odd", "even">; // ➔ "odd" * type D = IfOdd<4, "odd", "even">; // ➔ "even" * ``` */ type IfOdd = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfPositive`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is ***positive***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfPositive<10>; // ➔ true * type B = IfPositive<-5>; // ➔ false * type C = IfPositive<10, "yes", "no">; // ➔ "yes" * type D = IfPositive<-5, "yes", "no">; // ➔ "no" * ``` */ type IfPositive = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfNegative`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is ***negative***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfNegative<-10>; // ➔ true * type B = IfNegative<5>; // ➔ false * type C = IfNegative<-10, "yes", "no">; // ➔ "yes" * type D = IfNegative<5, "yes", "no">; // ➔ "no" * ``` */ type IfNegative = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfPositiveInteger`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is a ***positive integer***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfPositiveInteger<42>; // ➔ true * type B = IfPositiveInteger<-5>; // ➔ false * type C = IfPositiveInteger<42, "yes", "no">; // ➔ "yes" * type D = IfPositiveInteger<-5, "yes", "no">; // ➔ "no" * ``` */ type IfPositiveInteger = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfNegativeInteger`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is a ***negative integer***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`) . * @example * ```ts * type A = IfNegativeInteger<-42>; // ➔ true * type B = IfNegativeInteger<5>; // ➔ false * type C = IfNegativeInteger<-42, "yes", "no">; // ➔ "yes" * type D = IfNegativeInteger<5, "yes", "no">; // ➔ "no" * ``` */ type IfNegativeInteger = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfPositiveFloat`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is a ***positive float***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfPositiveFloat<3.14>; // ➔ true * type B = IfPositiveFloat<-2.5>; // ➔ false * type C = IfPositiveFloat<3.14, "yes", "no">; // ➔ "yes" * type D = IfPositiveFloat<-2.5, "yes", "no">; // ➔ "no" * ``` */ type IfPositiveFloat = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfNegativeFloat`.*** * ------------------------------------------------------- * **Conditional: selects one of two branches depending on whether `T` is a ***negative float***.** * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - A number type. * @template IfTrue - The branch type if condition is met, (default: `true`). * @template IfFalse - The branch type if condition is not met, (default: `false`). * @example * ```ts * type A = IfNegativeFloat<-3.14>; // ➔ true * type B = IfNegativeFloat<2.5>; // ➔ false * type C = IfNegativeFloat<-3.14, "yes", "no">; // ➔ "yes" * type D = IfNegativeFloat<2.5, "yes", "no">; // ➔ "no" * ``` */ type IfNegativeFloat = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `ParseNumber`.*** * -------------------------------------------------------- * **Converts a string or property key literal into a ***number literal***.** * - **Behavior:** * - Supports decimal numbers only. * - Automatically trims whitespace. * - Returns the number literal if valid. * - Supports scientific notation strings (e.g., `"2e-3"`, `"-5e2"`, `"2E-3"`, `"-5E2"`). * - **Note:** * - TypeScript cannot represent very small (`< 1e-6`) or very large (`> 1e15`) * numbers as literal types: * - In such cases, scientific notation strings return `0`. * - Returns `0` for strings representing hexadecimal (`0x...`), octal (`0o...`), or * binary (`0b...`) if they are string literals. * - Returns `never` for non-numeric strings or unsupported formats. * @template T - A string, number, or symbol (property key). * @example * ```ts * // Number: * type A = ParseNumber<0>; // ➔ 0 * type B = ParseNumber<-0>; // ➔ 0 * type C = ParseNumber<-0.>; // ➔ 0 * type D = ParseNumber<42>; // ➔ 42 * type E = ParseNumber<0.42>; // ➔ 0.42 * type F = ParseNumber<-5>; // ➔ -5 * type G = ParseNumber<-2.5>; // ➔ -2.5 * type H = ParseNumber<2.5e3>; // ➔ 2500 * type I = ParseNumber<-2.5e3>;// ➔ -2500 * type J = ParseNumber<5e3>; // ➔ 5000 * type K = ParseNumber<-5e3>; // ➔ -5000 * type L = ParseNumber<5e21>; // ➔ 5e+21 * type M = ParseNumber<5e-3>; // ➔ 0.005 * type N = ParseNumber<5e-21>; // ➔ 5e-21 * type O = ParseNumber<-5e-3>; // ➔ -0.005 * * // Numeric String: * type A = ParseNumber<"0">; // ➔ 0 * type B = ParseNumber<"-0">; // ➔ 0 * type C = ParseNumber<"42">; // ➔ 42 * type D = ParseNumber<"0.42">; // ➔ 0.42 * type E = ParseNumber<"-42">; // ➔ -42 * type F = ParseNumber<"-0.42">; // ➔ -0.42 * type G = ParseNumber<" 42 ">; // ➔ 42 * type H = ParseNumber<" -42 ">; // ➔ -1 * * // Scientific notation string: * type S1 = ParseNumber<"2e3">; // ➔ 2000 * type S2 = ParseNumber<"-2e3">; // ➔ -2000 * type S3 = ParseNumber<"2e-3">; // ➔ 0.002 * type S4 = ParseNumber<"-2e-3">; // ➔ -0.002 * type S5 = ParseNumber<"2.5e3">; // ➔ 0 * type S6 = ParseNumber<"2.5e-3">; // ➔ 0 * type S7 = ParseNumber<"2e-7">; // ➔ 0 (too small include "-2e-7" for TypeScript literal) * type S8 = ParseNumber<"5e21">; // ➔ 0 (too large include "-5e21" for TypeScript literal) * * // Number representing hexadecimal, octal or binary: * type A = ParseNumber<"011">; // ➔ 9 (same as octal but deprecated) * type B = ParseNumber<"0o11">; // ➔ 9 (octal) * type C = ParseNumber<"-0o11">; // ➔ -9 (octal) * type D = ParseNumber<"0x12">; // ➔ 18 (hexadecimal) * type E = ParseNumber<"-0x12">; // ➔ -18 (hexadecimal) * type F = ParseNumber<"0b111">; // ➔ 7 (binary) * type G = ParseNumber<"-0b111">; // ➔ -7 (binary) * * // String representing hexadecimal, octal or binary: * type A = ParseNumber<"0x2A">; // ➔ 0 (hex on string not supported) * type B = ParseNumber<"0o52">; // ➔ 0 (octal on string not supported) * type C = ParseNumber<"0b101010">; // ➔ 0 (binary on string not supported) * * // Never Result * type A = ParseNumber; // ➔ never * type B = ParseNumber; // ➔ never * type C = ParseNumber<"abc">; // ➔ never * type D = ParseNumber<"a1">; // ➔ never * type E = ParseNumber<"3b">; // ➔ never * ``` */ type ParseNumber = T extends bigint ? T : If>>, Extends<-0, T>, Extends]>, true, 0, T extends `${"-" | ""}0${"x" | "b" | "o"}${number}` ? 0 : Trim> extends `${infer NumT extends number | string}` ? T extends `${infer N extends number}.` ? N : NumT extends string ? ParseScientificNumber : NumT : Trim> extends number ? T : never>, never>; /** ------------------------------------------------------- * * ***Utility Type: `IsScientificNumber`.*** * ------------------------------------------------------- * **Checks if a string literal `T` represents a **scientific number**.** * - **A scientific number is defined as a number in the form of:** * - Optional negative sign (`-`). * - Mantissa (digits, can be integer or decimal). * - Exponent indicated by `e` or `E`. * - Exponent value (digits, optional negative sign). * - **Important:** * - TypeScript cannot detect numeric literals in scientific notation * at type-level because number literals are normalized to decimals: * - Only string literals like `"2.5E3"` or `"-1e-5"` can be detected. * @template T - A string literal to check. * @example * ```ts * type A = IsScientificNumber<"1e5">; // ➔ true * type B = IsScientificNumber<"-1e-5">; // ➔ true * type C = IsScientificNumber<"2.5E3">; // ➔ true * type D = IsScientificNumber<"42">; // ➔ false * type E = IsScientificNumber<"-0.42">; // ➔ false * type F = IsScientificNumber; // ➔ false * ``` * @remarks * - Uses template literal types and conditional type {@link Extends | **`Extends`**}. * - Returns `true` if `T` is scientific number string literal, otherwise `false`. * - Returns `boolean` if `T` is generic `string`. */ type IsScientificNumber = Extends; /** * ***Helper for {@link ParseScientificNumber | **`ParseScientificNumber`**}.*** * */ type BuildTuple = T["length"] extends L ? T : BuildTuple; /** * ***Helper for {@link ParseScientificNumber | **`ParseScientificNumber`**}.*** * */ type _DecrementParseScientific = BuildTuple extends [infer _, ...infer Rest] ? Rest["length"] : never; /** ------------------------------------------------------- * * ***Utility Type: `ParseScientificNumber`.*** * ------------------------------------------------------- * **Converts a numeric string in scientific notation (e.g., `"2e-3"`, `"-5e2"`) * into a literal number type.** * - **Important:** * - TypeScript cannot represent very small or very large numbers * as literal types: * - In such cases, this utility will return `0`. * @template T - A numeric string to parse. Can be in: * - Positive or negative scientific notation (e.g., `"1e3"`, `"-2e-2"`). * - Regular number literal (e.g., `"42"`, `"-5"`). * @example * ```ts * type A1 = ParseScientificNumber<"2e-3">; // ➔ 0.002 * type A2 = ParseScientificNumber<"-2e-3">; // ➔ -0.002 * type A3 = ParseScientificNumber<"5e2">; // ➔ 500 * type A4 = ParseScientificNumber<"-5e2">; // ➔ -500 * type A5 = ParseScientificNumber<"2e-7">; // ➔ 0 (TypeScript cannot represent literal) * type A6 = ParseScientificNumber<"5e21">; // ➔ 0 (TypeScript cannot represent literal) * type A7 = ParseScientificNumber<"42">; // ➔ 42 * type A8 = ParseScientificNumber<"-42">; // ➔ -42 * ``` * @remarks * - Uses type-level string manipulation to handle scientific notation. * - Negative exponents are adjusted with {@link _DecrementParseScientific | **`_DecrementParseScientific`**} and * {@link Repeat | **`Repeat`**}. * - Returns `0` if TypeScript cannot infer the exact numeric literal. */ type ParseScientificNumber = T extends `-${infer Mantissa}${"e" | "E"}-${infer Exp extends number}` ? `-${"0."}${Repeat<"0", _DecrementParseScientific>}${Mantissa}` extends `${infer N extends number}` ? number extends N ? 0 : N : never : T extends `${infer Mantissa}${"e" | "E"}-${infer Exp extends number}` ? `0.${Repeat<"0", _DecrementParseScientific>}${Mantissa}` extends `${infer N extends number}` ? number extends N ? 0 : N : never : T extends `-${infer Mantissa}${"e" | "E"}${infer Exp extends number}` ? `-${Mantissa}${Repeat<"0", Exp>}` extends `${infer N extends number}` ? number extends N ? 0 : N : never : T extends `${infer Mantissa}${"e" | "E"}${infer Exp extends number}` ? `${Mantissa}${Repeat<"0", Exp>}` extends `${infer N extends number}` ? number extends N ? 0 : N : never : T extends `${infer N extends number}` ? number extends N ? 0 : N : never; /** ------------------------------------------------------- * * ***Utility Type: `Abs`.*** * ------------------------------------------------------- * **Computes the ***absolute value*** of `T`.** * - **Behavior:** * - Accepts `number` literals or numeric `string` literals. * - Returns the ***absolute value*** as a `number`. * - If `T` is not a valid number, ***`like`***: * - `hex`, `binary`, `octal`, or `non-numeric string` will return `never`. * @template T - A number type or string literal representing a number. * @example * ```ts * type A = Abs<-42>; // ➔ 42 * type B = Abs<10>; // ➔ 10 * type C = Abs<"11">; // ➔ 11 * type D = Abs<"-11">; // ➔ 11 * * // Not a number * type Invalid1 = Abs<"1a">; // ➔ never * type Invalid2 = Abs<"a1">; // ➔ never * type Invalid3 = Abs<"a1a">; // ➔ never * type Invalid4 = Abs<"abc">; // ➔ never * type Invalid5 = Abs; // ➔ never * type Invalid6 = Abs; // ➔ never * ``` */ type Abs = `${Exclude}` extends `-${infer PositiveT extends number}` ? ParseNumber : ParseNumber; /** ------------------------------------------------------- * * ***Utility Type: `Negate`.*** * ------------------------------------------------------- * **Produces the ***negated value*** of `T` (multiplies by `-1`).** * - **Behavior:** * - Only supports valid **number literals** or **numeric-strings**. * - Invalid numeric-strings (***like***: `"1a"`, `"abc"`, `hex`, `binary`, `octal`) * or `non-numeric` types, ***`like`***: * - `string`, `number`, `symbol` will return `0`. * @template T - A number type or numeric-string. * @example * ```ts * type A = Negate<5>; // ➔ -5 * type B = Negate<-10>; // ➔ -10 * type C = Negate<0>; // ➔ 0 * type D = Negate<-0>; // ➔ 0 * type E = Negate<"123">; // ➔ -123 * * // Not a number or numeric-string: * type Invalid1 = Negate; // ➔ 0 * type Invalid2 = Negate; // ➔ 0 * type Invalid3 = Negate<"abc">; // ➔ 0 * type Invalid4 = Negate<"1a">; // ➔ 0 * type Invalid5 = Negate<"2b">; // ➔ 0 * type Invalid6 = Negate<"0x1f">; // ➔ 0 * type Invalid7 = Negate<"0b101">; // ➔ 0 * type Invalid8 = Negate<"0o77">; // ➔ 0 * ``` */ type Negate = ParseNumber<`-${Abs>}`>; /** ------------------------------------------------------- * * ***Utility Type: `Stringify`.*** * ------------------------------------------------------- * **Converts a value of type `number`, `boolean`, `string`, `bigint`, `undefined`, or `null` into a string literal type.** * - **Behavior:** * - `number` ➔ string representation (e.g., `123` ➔ `"123"`) * - `boolean` ➔ `"true"` or `"false"` * - `string` ➔ itself * - `bigint` ➔ string representation with `"n"` suffix (e.g., `123n` ➔ `"123n"`) * - `undefined` ➔ `"undefined"` * - `null` ➔ `"null"` * - Other types ➔ `never` * @template T - The value type to stringify. * @example * ```ts * // Boolean * type Result1 = Stringify; * // ➔ "true" * * // Number * type Result2 = Stringify<123>; * // ➔ "123" * * // BigInt * type Result3 = Stringify<123n>; * // ➔ "123n" * * // String * type Result4 = Stringify<"hello">; * // ➔ "hello" * * // Undefined * type Result5 = Stringify; * // ➔ "undefined" * * // Null * type Result6 = Stringify; * // ➔ "null" * * // Other type * type Result7 = Stringify<{}>; * // ➔ never * ``` */ type Stringify = T extends number | boolean | string | bigint | undefined | null ? T extends bigint ? `${T}n` : `${T}` : never; type DecrementMap = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]; type NegativeCarryMap = { "-1": 9; }; /** ------------------------------------------------------- * * ***Internal Utility Type: `_Decrement (Internal / Deprecated)`*** * ------------------------------------------------------- * **Internal type-level utility to decrement a numeric string by 1.** * - **⚠️ Deprecated:** * - Do **not** use this directly. * - Use the public {@link Decrement | **`Decrement`**} type instead. * - Processes the string recursively digit by digit. * - Handles borrow/carry using internal `DecrementMap` and `NegativeCarryMap`. * @template Number - The numeric string to decrement. * @template Result - (Internal) Accumulator used during recursion. * @deprecated Use {@link Decrement | **`Decrement`**} instead. * @example * ```ts * // ❌ Avoid using _Decrement directly * type R1 = _Decrement<"23">; * * // ✅ Use Decrement instead * type R2 = Decrement<"23">; // ➔ 22 * ``` */ type _Decrement = Number extends "" ? ParseNumber : ParseNumber> extends infer LastDigit extends number ? DecrementMap[LastDigit] extends infer Decremented extends number ? Number extends `${infer Rest}${LastDigit}` ? `${Decremented}` extends keyof NegativeCarryMap ? _Decrement : `${Rest}${Decremented}${Result}` extends infer FinalResult extends string ? ParseNumber : never : never : never : never; type _DecrementNegativeOrZero = _Increment> extends infer PositiveDecrementResult extends number ? PositiveDecrementResult extends 0 ? PositiveDecrementResult : Negate : never; /** ------------------------------------------------------- * * ***Utility Type: `Decrement`.*** * -------------------------------------------------------- * **A type-level utility that returns the decremented value of an integer.** * - Works for numbers in the range `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template T - The number type to decrement. * @example * ```ts * type A = Decrement<6>; // ➔ 5 * type B = Decrement<0>; // ➔ -1 * type C = Decrement<-6>; // ➔ -7 * type D = Decrement<123>; // ➔ 122 * type E = Decrement<-1>; // ➔ -2 * ``` */ type Decrement = IsNegative extends true ? _DecrementNegativeOrZero> : T extends 0 ? _DecrementNegativeOrZero : _Decrement>; type IncrementMap = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; type LastDigitMap = { 10: 0; }; /** ------------------------------------------------------- * * ***Internal Utility Type: `_Increment (Internal / Deprecated)`*** * ------------------------------------------------------- * **Internal type-level utility to increment a numeric string by 1.** * - **⚠️ Deprecated:** * - Do **not** use this directly. * - Use the public {@link Increment | **`Increment`**} type instead. * - Processes the string recursively digit by digit. * - Handles carry-over using internal `IncrementMap` and `LastDigitMap`. * @template Number - The numeric string to increment. * @template Result - (Internal) Accumulator used during recursion. * @deprecated Use {@link Increment | **`Increment`**} instead. * @example * ```ts * // ❌ Avoid using _Increment directly * type R1 = _Increment<"23">; * * // ✅ Use Increment instead * type R2 = Increment<"23">; // ➔ 24 * ``` */ type _Increment = IsEmptyString extends true ? ParseNumber<`1${Result}`> : LastCharacter extends `${infer LastDigit extends number}` ? IncrementMap[LastDigit] extends infer Incremented extends number ? Number extends `${infer Rest}${LastDigit}` ? Incremented extends keyof LastDigitMap ? _Increment : ParseNumber<`${Rest}${Incremented}${Result}`> : never : never : never; /** ------------------------------------------------------- * * ***Utility Type: `Increment`.*** * ------------------------------------------------------- * **Accepts an integer and returns the incremented value of it.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @template T - The input number to increment. * @example * ```ts * type Case1 = Increment<1>; // ➔ 2 * type Case2 = Increment<-10>; // ➔ -9 * ``` */ type Increment = IsNegative extends true ? _Decrement>> extends infer NegativeIncrementResult extends number ? NegativeIncrementResult extends 0 ? NegativeIncrementResult : Negate : never : _Increment>; /** ------------------------------------------------------- * * ***Utility Type: `GetFloatNumberParts`.*** * ------------------------------------------------------- * **Returns a tuple of the **whole** and **fraction** parts of a float number `T`.** * - **Behavior:** * - Only works for **float numbers** (i.e., numbers with a fractional part): * - If `T` is not a float, the result is `never`. * - Preserves the sign on the whole part (e.g. `-12.25` ➔ `[-12, 25]`). * - For values like `-0.x`, the TypeScript will normalizes `-0` to `0`, * so the result will be `[0, ...]`. * @template T - A float number type. * @example * ```ts * type A = GetFloatNumberParts<12.25>; // ➔ [12, 25] * type B = GetFloatNumberParts<-12.25>; // ➔ [-12, 25] * type C = GetFloatNumberParts<3.1415>; // ➔ [3, 1415] * type D = GetFloatNumberParts<-0.75>; // ➔ [0, 75] (`-0` normalized to `0`) * type E = GetFloatNumberParts<42>; // ➔ never (not a float) * ``` */ type GetFloatNumberParts = IsFloat extends true ? `${T}` extends `${infer Whole extends number}.${infer Fraction extends number}` ? [IsNegative extends true ? Whole : Whole, Fraction] : never : never; /** ------------------------------------------------------- * * ***Utility Type: `Ceil`.*** * ------------------------------------------------------- * **A type-level utility that computes the **mathematical ceiling** * of a numeric literal type `T`, type version of `Math.ceil()`.** * - **Behavior:** * - If `T` is an integer, it returns `T` unchanged. * - If `T` is a positive float, it rounds up to the nearest integer. * - If `T` is a negative float, it rounds up toward zero. * @template T - A number literal type. * @example * ```ts * type A = Ceil<1.2>; // ➔ 2 * type B = Ceil<1.9>; // ➔ 2 * type C = Ceil<5>; // ➔ 5 * type D = Ceil<-1.2>; // ➔ -1 * type E = Ceil<-1.9>; // ➔ -1 * type F = Ceil<-5>; // ➔ -5 * ``` */ type Ceil = IsFloat extends true ? GetFloatNumberParts extends [infer Whole extends number, unknown] ? IsNegative extends true ? Negate : Increment : never : T; /** ------------------------------------------------------- * * ***Utility Type: `Split`*** * ------------------------------------------------------- * **A type-level utility that mimics `String.prototype.split()`.** * @description * Splits a string literal `Str` into a tuple of substrings, * using `Del` as the delimiter. * - **Behavior:** * - If `Del` is the empty string `""`, the result is a tuple of characters. * - If `Del` is not found in `Str`, the result is a tuple with the original string. * - Works only with string literals. If `Str` is just `string`, the result is `string[]`. * @template Str - The input string literal to be split. * @template Del - The delimiter used to split the string. * Defaults to `""` (character-level split). * @constraints * - `Str` must be a string literal to get precise results. * - `Del` can be a string or number (numbers are converted to strings). * @example * ```ts * // ✅ Split into characters * type A = Split<"abc">; // ➔ ["a", "b", "c"] * * // ✅ Split by a comma * type B = Split<"a,b,c", ",">; // ➔ ["a", "b", "c"] * * // ✅ Split by multi-char delimiter * type C = Split<"2025-08-22", "-">; // ➔ ["2025", "08", "22"] * * // ✅ Delimiter not found ➔ returns whole string * type D = Split<"hello", "|">; // ➔ ["hello"] * * // ⚠️ Non-literal string * type E = Split; // string[] * ``` */ type Split = string extends Str ? string[] : "" extends Str ? [] : Str extends `${infer T}${Del}${infer U}` ? [T, ...Split] : [Str]; /** @private ***types for {@link CharAt}.*** * */ type _CharAt> = IfExtends>, true>, Extends, Extends, true>>, true>>, true, _S[Extract], undefined>; /** ------------------------------------------------------- * * ***Utility Type: `CharAt`.*** * ------------------------------------------------------- * **A type-level utility that extracts the character at a given index `N` * from a string literal type `I`.** * - **Behavior:** * - If the index is out of range, the result is `undefined`. * - If `I` is not a literal string (just `string`), the result is `undefined`. * - Only **positive indices** are supported (`0` and above`). * @template I - The input string literal to extract the character from. * @template N - The zero-based index of the character to retrieve. * @example * ```ts * // ✅ Basic usage * type A = CharAt<"hello", 0>; // ➔ "h" * type B = CharAt<"hello", 1>; // ➔ "e" * type C = CharAt<"hello", 4>; // ➔ "o" * * // ⚠️ Index out of range ➔ undefined * type D = CharAt<"hello", 5>; // ➔ undefined * type E = CharAt<"abc", 99>; // ➔ undefined * * // ✅ Stringified index also works * type F = CharAt<"testing", "0">; // ➔ "t" * type G = CharAt<"testing", "2">; // ➔ "s" * type H = CharAt<"testing", "6">; // ➔ "g" * type I = CharAt<"testing", "7">; // ➔ undefined * * // ⚠️ Non-literal strings ➔ undefined * type J = CharAt; // ➔ undefined * * // ⚠️ Negative indices are not supported * type K = CharAt<"abc", -1>; // ➔ undefined * ``` */ type CharAt = _CharAt; /** ------------------------------------------------------- * * ***Utility Type: `ColorCssNamed`.*** * ------------------------------------------------------- * **Represents a **named CSS color keyword**, including `transparent`.** * @description * This type includes all standard color names defined in the CSS Color Module Level 4 * specification, and ensures type safety for string values in strongly typed UI libraries, * themes, or design systems. * - **Behavior:** * - Only recognized, browser-supported named colors are allowed. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/named-color * @see https://drafts.csswg.org/css-color-4/#named-colors * @example * ```ts * const textColor1: ColorCssNamed = "rebeccapurple"; // ➔ ✅ valid * const textColor2: ColorCssNamed = "navy"; // ➔ ✅ valid * const textColor3: ColorCssNamed = "superblue"; // ➔ ❌ Type error * * // Usage in a theme object * const theme: Record = { * primary: "blue", * secondary: "goldenrod", * highlight: "transparent", * }; * ``` */ type ColorCssNamed = "aliceblue" | "antiquewhite" | "aqua" | "aquamarine" | "azure" | "beige" | "bisque" | "black" | "blanchedalmond" | "blue" | "blueviolet" | "brown" | "burlywood" | "cadetblue" | "chartreuse" | "chocolate" | "coral" | "cornflowerblue" | "cornsilk" | "crimson" | "cyan" | "darkblue" | "darkcyan" | "darkgoldenrod" | "darkgray" | "darkgreen" | "darkgrey" | "darkkhaki" | "darkmagenta" | "darkolivegreen" | "darkorange" | "darkorchid" | "darkred" | "darksalmon" | "darkseagreen" | "darkslateblue" | "darkslategray" | "darkslategrey" | "darkturquoise" | "darkviolet" | "deeppink" | "deepskyblue" | "dimgray" | "dimgrey" | "dodgerblue" | "firebrick" | "floralwhite" | "forestgreen" | "fuchsia" | "gainsboro" | "ghostwhite" | "gold" | "goldenrod" | "gray" | "green" | "greenyellow" | "grey" | "honeydew" | "hotpink" | "indianred" | "indigo" | "ivory" | "khaki" | "lavender" | "lavenderblush" | "lawngreen" | "lemonchiffon" | "lightblue" | "lightcoral" | "lightcyan" | "lightgoldenrodyellow" | "lightgray" | "lightgreen" | "lightgrey" | "lightpink" | "lightsalmon" | "lightseagreen" | "lightskyblue" | "lightslategray" | "lightslategrey" | "lightsteelblue" | "lightyellow" | "lime" | "limegreen" | "linen" | "magenta" | "maroon" | "mediumaquamarine" | "mediumblue" | "mediumorchid" | "mediumpurple" | "mediumseagreen" | "mediumslateblue" | "mediumspringgreen" | "mediumturquoise" | "mediumvioletred" | "midnightblue" | "mintcream" | "mistyrose" | "moccasin" | "navajowhite" | "navy" | "oldlace" | "olive" | "olivedrab" | "orange" | "orangered" | "orchid" | "palegoldenrod" | "palegreen" | "paleturquoise" | "palevioletred" | "papayawhip" | "peachpuff" | "peru" | "pink" | "plum" | "powderblue" | "purple" | "rebeccapurple" | "red" | "rosybrown" | "royalblue" | "saddlebrown" | "salmon" | "sandybrown" | "seagreen" | "seashell" | "sienna" | "silver" | "skyblue" | "slateblue" | "slategray" | "slategrey" | "snow" | "springgreen" | "steelblue" | "tan" | "teal" | "thistle" | "tomato" | "transparent" | "turquoise" | "violet" | "wheat" | "white" | "whitesmoke" | "yellow" | "yellowgreen"; /** ------------------------------------------------------- * * ***Utility Type: `IsEqual`.*** * ------------------------------------------------------- * **A type-level utility that returns a boolean indicating * whether the two types are ***equal***.** * @template T - The first type to compare. * @template U - The second type to compare. * @example * ```ts * type A = IsEqual; * // ➔ true * type B = IsEqual<1, 4>; * // ➔ false * type C = IsEqual; * // ➔ false * type D = IsEqual; * // ➔ true * ``` */ type IsEqual = (() => F extends T ? 1 : 2) extends (() => F extends U ? 1 : 2) ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `IsNotEqual`.*** * ------------------------------------------------------- * **A type-level utility that returns a boolean indicating * whether the two types are ***not equal***.** * @template T - The first type to compare. * @template U - The second type to compare. * @example * ```ts * type A = IsNotEqual<1, 4>; * // ➔ true * type B = IsNotEqual; * // ➔ false * ``` */ type IsNotEqual = Not>; /** ------------------------------------------------------- * * ***Utility Type: `IfEqual`.*** * ------------------------------------------------------- * - **Conditional:** * - Selects one of two branches depending on whether `T` and `U` are ***equal***. * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - The first type to compare. * @template U - The second type to compare. * @template IfTrue - The branch type if condition is met. (default: `true`) * @template IfFalse - The branch type if condition is not met. (default: `false`) * @example * ```ts * type A = IfEqual; // ➔ "valid" * type B = IfEqual<1, 4, "valid", "invalid">; // ➔ "invalid" * ``` */ type IfEqual = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IfNotEqual`.*** * ------------------------------------------------------- * - **Conditional:** * - Selects one of two branches depending on whether `T` and `U` are ***not equal***. * - Defaults: `IfTrue = true`, `IfFalse = false`. * @template T - The first type to compare. * @template U - The second type to compare. * @template IfTrue - The branch type if condition is met. (default: `true`) * @template IfFalse - The branch type if condition is not met. (default: `false`) * @example * ```ts * type A = IfNotEqual<1, 4, "valid">; * // ➔ "valid" * type B = IfNotEqual; * // ➔ "invalid" * ``` */ type IfNotEqual = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IsUnknown`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether the given type `T` is `unknown`.** * @template T - The type to check. * @example * ```ts * type TrueResult = IsUnknown; // ➔ true * type FalseResult1 = IsUnknown; // ➔ false * type FalseResult2 = IsUnknown; // ➔ false * ``` */ type IsUnknown = IsAny extends true ? false : [unknown] extends [T] ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `IfUnknown`.*** * ------------------------------------------------------- * - **Conditional type:** * - Returns `IfTrue` if `T` is `unknown`, otherwise returns `IfFalse`. * @template T - The type to check. * @template IfTrue - The type returned if `T` is `unknown` (default: `true`). * @template IfFalse - The type returned if `T` is not `unknown` (default: `false`). * @example * ```ts * type Result1 = IfUnknown; // ➔ "foo" * type Result2 = IfUnknown; // ➔ "bar" * ``` */ type IfUnknown = If, IfTrue, IfFalse>; /** --------------------------------------------------------------------------- * * ***Type Options for {@link UnknownifyProperties | `UnknownifyProperties`}.*** * --------------------------------------------------------------------------- * @property makeOptional - If `true`, all properties become optional. */ type UnknownifyPropertiesOptions = { /** * If `true`, all properties of the object become optional. * * DefaultValue: `false`. * * @default false * @example * ```ts * type A = { a: string; b: number }; * type B = UnknownifyProperties; * // ➔ { a?: unknown; b?: unknown } * ``` */ makeOptional: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `UnknownifyProperties`.*** * ------------------------------------------------------- * **Transforms all properties of an object type `T` to `unknown`.** * @description Optionally, makes all properties optional based on `Options`. * @template T - The object type to transform. * @template Options - Configuration options (default: `{ makeOptional: false }`). * * @example * ```ts * type A = { a: string; b: number }; * type Result1 = UnknownifyProperties; * // ➔ { a: unknown; b: unknown } * type Result2 = UnknownifyProperties; * // ➔ { a?: unknown; b?: unknown } * ``` */ type UnknownifyProperties = { [K in keyof T]: unknown } extends infer Result ? If, Result> : never; /** ------------------------------------------------------- * * ***Utility Type: `IsExactly`.*** * ------------------------------------------------------- * **A strict equality check between two types `A` and `B` * that does **not** collapse when one of them is `any`.** * - **Behavior:** * - Returns `true` only if `A` and `B` are **mutually assignable**. * - Returns `false` if either `A` or `B` is `any`. * @template A - The first type to compare. * @template B - The second type to compare. * @example * ```ts * type A = IsExactly; // ➔ true * type B = IsExactly; // ➔ false * type C = IsExactly<42, number>; // ➔ false * type D = IsExactly; // ➔ true * type E = IsExactly; // ➔ false * ``` */ type IsExactly = IsAny extends true ? false : IsAny extends true ? false : (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? (() => T extends B ? 1 : 2) extends (() => T extends A ? 1 : 2) ? true : false : false; declare global { namespace NodeJS { interface EventEmitter {} interface ReadableStream {} interface WritableStream {} interface Process {} } interface Buffer {} } type Global = K extends keyof typeof globalThis ? (typeof globalThis)[K] : never; type Empty = keyof T extends never ? never : T; /** -------------------------------------------------- * * ***Utility Type: `NodeBuiltins`.*** * -------------------------------------------------- * Represents commonly used Node.js runtime objects * when Node.js type definitions are available. * * @description * Includes frequently encountered Node.js core objects * and runtime-related built-ins. * * - **Examples:** * - `Buffer` * - `EventEmitter` * - `ReadableStream` * - `WritableStream` * - `process` * - `URL` * * - ❌ Excludes: * - Plain objects (`{}`) * - Primitive values * - Most Node.js modules/classes * * - ⚠️ Notes: * - This type is intentionally **not exhaustive**. * - Missing Node.js types automatically resolve to `never`. * - `URL` is always included because it exists in both * browser and Node.js environments. */ type NodeBuiltins = Empty> | Empty | Empty | Empty | Empty | URL; /** -------------------------------------------------- * * ***Utility Type: `DataTypes`.*** * -------------------------------------------------- * **Represents a broad union of commonly used JavaScript data types.** * - ✅ ***Includes:*** * - `Primitive-Types`. * - `object`. * - `null`. * - `undefined`. * - `symbol`. * - `Any-Function` signature. * @example * ```ts * function isValidType(value: DataTypes): boolean { * return value !== undefined && value !== null; * } * ``` */ type DataTypes = bigint | boolean | AnyFunction | null | number | object | string | symbol | undefined; /** -------------------------------------------------- * * ***Utility Type: `DeepReplaceType`.*** * -------------------------------------------------- * **Recursively traverses an array, tuple, or object (including nested structures) * and replaces all values of type `Target` with `NewType`.** * - ✅ Useful for remapping deeply nested arrays, tuples, or records. * @template Arr - The input array, tuple, or object. * @template Target - The type to match and replace. * @template NewType - The new type to assign to matched values. * @example * ```ts * // Simple tuple * type A = [number, string, [number]]; * type B = DeepReplaceType; * // ➔ [boolean, string, [boolean]] * * // Nested object * type Obj = { a: number; b: { c: number; d: string } }; * type ObjReplaced = DeepReplaceType; * // ➔ { a: boolean; b: { c: boolean; d: string } } * * // Mixed array and object * type Mixed = [{ x: number }, { y: string, z: number[] }]; * type MixedReplaced = DeepReplaceType; * // ➔ [{ x: boolean }, { y: string, z: boolean[] }] * ``` */ type DeepReplaceType = Arr extends Target ? NewType : Arr extends object ? { [K in keyof Arr]: DeepReplaceType } : Arr; /** -------------------------------------------------- * * ***Utility Type: `TypedArray`.*** * -------------------------------------------------- * **Represents all JavaScript **TypedArray** types used for binary data manipulation.** * - ✅ ***Includes:*** * - `Int8Array`. * - `Uint8Array`. * - `Uint8ClampedArray`. * - `Int16Array`. * - `Uint16Array`. * - `Int32Array`. * - `Uint32Array`. * - `Float32Array`. * - `Float64Array`. * - `BigInt64Array`. * - `BigUint64Array`. */ type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array; /** -------------------------------------------------- * * ***Utility Type: `WebApiObjects`.*** * -------------------------------------------------- * **Represents common **Web API objects** available in the browser.** * - ✅ ***Includes:*** * - URL: `URL`, `URLSearchParams`. * - Networking: `Request`, `Response`, `Headers`, `WebSocket`. * - Streams: `ReadableStream`, `WritableStream`, `TransformStream`. * - Events: `Event`, `CustomEvent`, `MessageChannel`, `MessagePort`, `MessageEvent`. * - DOM: `HTMLElement`, `Node`, `Document`, `Window`, `CanvasRenderingContext2D`. * - Encoding: `TextEncoder`, `TextDecoder`. * - File: `File`, `FileList`, `ImageBitmap`, `FormData`. * - Abort: `AbortController`, `AbortSignal`. * - Crypto: `CryptoKey`. */ type WebApiObjects = URL | URLSearchParams | FormData | Headers | Response | Request | ReadableStream | WritableStream | TransformStream | MessageChannel | MessagePort | MessageEvent | Event | CustomEvent | HTMLElement | Node | Document | Window | AbortController | AbortSignal | TextEncoder | TextDecoder | CryptoKey | File | FileList | ImageBitmap | CanvasRenderingContext2D | WebSocket; /** -------------------------------------------------- * * ***Utility Type: `IntlObjects`.*** * -------------------------------------------------- * **Represents all **ECMAScript Internationalization API** objects from `Intl`.** * - ✅ ***Includes:*** * - `Intl.Collator`. * - `Intl.DateTimeFormat`. * - `Intl.NumberFormat`. * - `Intl.RelativeTimeFormat`. * - `Intl.PluralRules`. * - `Intl.ListFormat`. (if environment is supported). * - `Intl.Locale`. (if environment is supported). */ type IntlObjects = { [K in keyof typeof Intl]: (typeof Intl)[K] extends (abstract new (...args: any[]) => infer R) ? R : never }[keyof typeof Intl]; /** -------------------------------------------------- * * ***Utility Type: `BoxedPrimitivesTypes`.*** * -------------------------------------------------- * **Represents JavaScript **boxed primitive objects** (object wrappers for primitive values).** * @description * Boxed primitives are created using the `new` keyword on primitive wrapper constructors. * - ✅ ***Includes (object wrappers):*** * - `new Number(123)` ➔ `Number`. * - `new String("hello")` ➔ `String`. * - `new Boolean(true)` ➔ `Boolean`. * - ❌ ***Excludes (primitive values):*** * - `123` ➔ `number`. * - `"hello"` ➔ `string`. * - `true` ➔ `boolean`. * - ℹ️ ***Note:*** * - These are **rarely used directly** in modern **JavaScript/TypeScript**. * - However, they exist for completeness and are sometimes relevant * when distinguishing between **primitive values** and **object wrappers**. * @example * ```ts * const a: BoxedPrimitivesTypes = new Number(123); * // ➔ ✅ valid * const b: BoxedPrimitivesTypes = new String("abc"); * // ➔ ✅ valid * const c: BoxedPrimitivesTypes = new Boolean(false); * // ➔ ✅ valid * * // ❌ Not allowed (primitive values): * const x: BoxedPrimitivesTypes = 123; * const y: BoxedPrimitivesTypes = "abc"; * const z: BoxedPrimitivesTypes = true; * ``` */ type BoxedPrimitivesTypes = Number | String | Boolean; /** -------------------------------------------------- * * ***Utility Type: `NonPlainObject`.*** * -------------------------------------------------- * **Represents all known **non-plain object types**, * i.e., values that are **not** considered a `"plain object"` (`{ [key: string]: any }`).** * - ✅ ***Includes:*** * - **Functions**. * - **Arrays**. * - **Native objects:** `Date`, `RegExp`, `Map`, `Set`, `WeakMap`, `WeakSet`. * - **Built-in classes & APIs:** `Promise`, `Error`, `ArrayBuffer`, `DataView`. * - **Typed arrays:** `TypedArray`. * - **Browser & Node APIs:** `WebApiObjects`, `IntlObjects`, `NodeBuiltins`. * - **Symbols**. * - **Proxies** (wrapping any object). * - The global **`Reflect`** object. * - ❌ ***Excludes:*** * - Plain objects (`{ foo: string }`, `Record`), `null` and `undefined`. * - ℹ️ ***Note:*** * - Use this type when you need to differentiate **plain objects** from **all other object-like values**. * @example * ```ts * type A = NonPlainObject; * * const x: A = new Date(); * // ➔ ✅ Allowed * const y: A = [1, 2, 3]; * // ➔ ✅ Allowed * const z: A = Promise.resolve(123); * // ➔ ✅ Allowed * * // ❌ Not allowed (plain object): * // const bad: A = { foo: "bar" }; * ``` */ type NonPlainObject = BoxedPrimitivesTypes | AnyFunction | Promise | Array | AnObjectNonArray; /** -------------------------------------------------- * * ***Utility Type: `AnObjectNonArray`.*** * -------------------------------------------------- * **Represents all **non-null, non-array, object-like values** in JavaScript/Node.js.** * - ✅ ***Includes:*** * - **Built-in objects:** `Date`, `RegExp`, `Error`, `ArrayBuffer`, `DataView`. * - **Collections:** `Map`, `Set`, `WeakMap`, `WeakSet`. * - **Typed arrays:** * `Int8Array`, `Uint8Array`, `Uint8ClampedArray`, * `Int16Array`, `Uint16Array`, * `Int32Array`, `Uint32Array`, * `Float32Array`, `Float64Array`, * `BigInt64Array`, `BigUint64Array`. * - **Browser Web APIs:** * `URL`, `URLSearchParams`, `FormData`, `Headers`, `Response`, `Request`, * `ReadableStream`, `WritableStream`, `TransformStream`, * `MessageChannel`, `MessagePort`, `MessageEvent`, * `Event`, `CustomEvent`, `HTMLElement`, `Node`, `Document`, `Window`, * `CanvasRenderingContext2D`, * `AbortController`, `AbortSignal`, * `TextEncoder`, `TextDecoder`, * `CryptoKey`, `File`, `FileList`, `ImageBitmap`, `WebSocket`. * - **ECMAScript Internationalization API objects:** * `Intl.Collator`, `Intl.DateTimeFormat`, `Intl.NumberFormat`, * `Intl.RelativeTimeFormat`, `Intl.PluralRules`, * `Intl.ListFormat`, `Intl.Locale`. * - **Node.js built-ins:** `Buffer`. * - **Symbols**. * - **Proxies** (wrapping any object). * - The global **`Reflect`** object. * - ❌ ***Excludes:*** * - `null`. * - Arrays (`[]`, `new Array()`). * - ℹ️ ***Note:*** * - Use this type when you need to represent **any object-like value except arrays and `null`**. * @example * ```ts * const a: AnObjectNonArray = new Date(); * const b: AnObjectNonArray = new Map(); * const c: AnObjectNonArray = Symbol("id"); * * // ❌ These are NOT allowed: * // const x: AnObjectNonArray = null; * // const y: AnObjectNonArray = []; * ``` */ type AnObjectNonArray = Date | RegExp | Map | Set | WeakMap | WeakSet | Error | ArrayBuffer | DataView | TypedArray | WebApiObjects | IntlObjects | NodeBuiltins | symbol | { [Symbol.toStringTag]: "Proxy"; } | typeof Reflect; /** ------------------------------------------------------- * * ***Utility Type: `IsGeneralArray`.*** * ------------------------------------------------------- * **Checks if `T` is a **general array type** (`X[]` or `ReadonlyArray`) * instead of a tuple literal.** * - **Behavior:** * - Returns `true` for `string[]`, `(number | boolean)[]`, `any[]`, etc. * - Returns `false` for tuples like `[]`, `[1, 2, 3]`, or `[string, number]`. * @template T - The type to check. * @example * ```ts * type A = IsGeneralArray; // ➔ true * type B = IsGeneralArray<[]>; // ➔ false * type C = IsGeneralArray<[1, 2, 3]>; // ➔ false * type D = IsGeneralArray>; // ➔ true * ``` */ type IsGeneralArray = T extends readonly unknown[] ? number extends T["length"] ? true : false : false; /** ------------------------------------------------------- * * ***Utility Type: `IsBaseType`.*** * ------------------------------------------------------- * **Determines whether a type `T` is considered a **base / keyword / built-in type** * rather than a literal, tuple, or specific instance.** * - **Behavior:** * - ***✅ Considered base types:*** * - Special keywords: `any`, `unknown`, `never`, `null`, `undefined`, `void` * - Primitive keywords: `string`, `number`, `boolean`, `bigint`, `symbol` * - Function keyword `Function` and alias `AnyFunction` * - General arrays (`X[]`, `ReadonlyArray`) and `TypedArray` * - Common built-ins: `Date`, `RegExp`, `Error` * - Generic containers: `Promise`, `Map`, `WeakMap`, `Set`, `WeakSet` * - Buffers & views: `ArrayBuffer`, `SharedArrayBuffer`, `DataView` * - `object` keyword and `{}` (empty object type) * - ***❌ Not considered base types:*** * - Literal values (`"foo"`, `123`, `true`) * - Union literals (`"a" | "b"`) * - Tuples (`[1, 2, 3]`, `[]`) * - Specific object shapes (`{ a: 1 }`, `{ x: string }`) * - Functions with explicit structure (`() => {}`, `(x: number) => string`) * @template T - The type to evaluate. * @example * ```ts * // Special keywords * type A = IsBaseType; // ➔ true * type B = IsBaseType; // ➔ true * type C = IsBaseType; // ➔ true * * // Primitives * type PS1 = IsBaseType; // ➔ true * type PS2 = IsBaseType<"hi">; // ➔ false * type PN1 = IsBaseType; // ➔ true * type PN2 = IsBaseType<42>; // ➔ false * type PB1 = IsBaseType; // ➔ true * type PB2 = IsBaseType; // ➔ false * type PB3 = IsBaseType; // ➔ false * type PBi1 = IsBaseType; // ➔ true * type PBi2 = IsBaseType<123n>; // ➔ false * * // Functions * type H = IsBaseType; // ➔ true * type I = IsBaseType; // ➔ true * type J = IsBaseType<() => {}>; // ➔ false * * // Arrays * type K = IsBaseType<[]>; // ➔ false * type L = IsBaseType; // ➔ true * type M = IsBaseType<(string | number)[]>; // ➔ true * * // Built-ins * type N = IsBaseType; // ➔ true * type O = IsBaseType; // ➔ false * type P = IsBaseType>; // ➔ true * type Q = IsBaseType>; // ➔ false * * // Objects * type R = IsBaseType; // ➔ true * type S = IsBaseType<{ a: 1 }>; // ➔ false * type T = IsBaseType<{}>; // ➔ true * ``` */ type IsBaseType = IsAny extends true ? true : IsUnknown extends true ? true : IsNever extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsGeneralArray extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : T extends Promise ? IsBaseType extends true ? true : false : T extends Map ? IsBaseType extends true ? IsBaseType extends true ? true : false : false : T extends WeakMap ? K extends object ? IsBaseType extends true ? true : false : false : T extends Set ? IsBaseType extends true ? true : false : T extends WeakSet ? U extends object ? true : false : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : IsExactly extends true ? true : [T] extends [object] ? [object] extends [T] ? true : false : false; /** * Helper for {@link ReplaceAll} */ type Includes$1 = S extends `${infer _}${Sub}${infer _}` ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `ReplaceAll`.*** * ------------------------------------------------------- * **A **type-level utility** that replaces all occurrences of a given string (or array of strings) `Pivot` in a string `T` with `ReplaceBy`.** * - **Supports:** * - Replacing a single substring. * - Replacing multiple substrings (Pivot as array). * - Guards against infinite recursion if `ReplaceBy` contains any value in Pivot. * @template T - The string to process. * @template Pivot - A string or readonly array of strings to replace. * @template ReplaceBy - The string to replace Pivot with. * @example * ```ts * // Single pivot string * type Case1 = ReplaceAll<'remove me me', 'me', 'him'>; * // ➔ 'remove him him' * * // Pivot as array * type Case2 = ReplaceAll<'remove me remove me', ['me', 'remove'], 'him'>; * // ➔ 'him him him him' * * // Pivot not found * type Case3 = ReplaceAll<'hello world', 'foo', 'bar'>; * // ➔ 'hello world' * * // ReplaceBy contains pivot (guard against infinite recursion) * type Case4 = ReplaceAll<'abc', 'a', 'a'>; * // ➔ string * ``` * @remarks * - Works recursively to replace all instances. * - If Pivot is empty (`""`) or empty array (`[]`), returns `T` unchanged. */ type ReplaceAll = Pivot extends "" | [] ? T : Includes$1 extends true ? string : Pivot extends readonly [infer First extends string, ...infer Rest extends string[]] ? ReplaceAll, Rest, ReplaceBy> : Pivot extends string ? T extends `${infer A}${Pivot}${infer B}` ? ReplaceAll<`${A}${ReplaceBy}${B}`, Pivot, ReplaceBy> : T : T; /** ------------------------------------------------------- * * ***Utility Type: `IsTuple`.*** * ------------------------------------------------------- * **Returns a boolean whether the first array argument is fixed length tuple.** * @template T - The array to check. * @example * type Case1 = IsTuple<[1, 2, 3]>; // ➔ true * type Case2 = IsTuple; // ➔ false */ type IsTuple = NotExtends; /** ------------------------------------------------------- * * ***Utility Type: `IfTuple`.*** * ------------------------------------------------------- * **Returns the second argument if the first array argument is fixed length * tuple (defaults to `true`), otherwise returns the third argument (defaults * to `false`).** * @template T - The array to check. * @template IfTrue - The branch type if condition is met. (default: `true`). * @template IfFalse - The branch type if condition is not met. (default: `false`). * @example * type Case1 = IfTuple<[1, 2, 3], 'valid'>; * // ➔ 'valid' * type Case2 = IfTuple; * // ➔ 'invalid' */ type IfTuple = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `RemoveLeading`.*** * ------------------------------------------------------- * **Accepts a string type `T` and **recursively removes leading characters** * specified in `Characters`.** * @template T - The string to process. * @template Characters - The characters to remove from the start. * @example * ```ts * type Case1 = RemoveLeading<'aaabc', 'a'>; * // ➔ 'bc' (all leading 'a' removed). * type Case2 = RemoveLeading<'abc', 'd'>; * // ➔ 'abc' (no 'd' at start, unchanged). * type Case3 = RemoveLeading<'aaa', 'a'>; * // ➔ '' (all 'a' removed). * type Case4 = RemoveLeading<'aaa', 'aa'>; * // ➔ 'a' (matches 'aa' once, then remaining 'a'). * ``` */ type RemoveLeading = T extends `${Characters}${infer Rest extends string}` ? IsEmptyString extends true ? Rest : RemoveLeading : T; type SubDecrementMap = { "-9": -10; "-8": -9; "-7": -8; "-6": -7; "-5": -6; "-4": -5; "-3": -4; "-2": -3; "-1": -2; "0": -1; "1": 0; "2": 1; "3": 2; "4": 3; "5": 4; "6": 5; "7": 6; "8": 7; "9": 8; }; type SubNegativeCarryMap = { "-10": 0; "-9": 1; "-8": 2; "-7": 3; "-6": 4; "-5": 5; "-4": 6; "-3": 7; "-2": 8; "-1": 9; }; type SubMap = { 0: [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]; 1: [1, 0, -1, -2, -3, -4, -5, -6, -7, -8]; 2: [2, 1, 0, -1, -2, -3, -4, -5, -6, -7]; 3: [3, 2, 1, 0, -1, -2, -3, -4, -5, -6]; 4: [4, 3, 2, 1, 0, -1, -2, -3, -4, -5]; 5: [5, 4, 3, 2, 1, 0, -1, -2, -3, -4]; 6: [6, 5, 4, 3, 2, 1, 0, -1, -2, -3]; 7: [7, 6, 5, 4, 3, 2, 1, 0, -1, -2]; 8: [8, 7, 6, 5, 4, 3, 2, 1, 0, -1]; 9: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]; }; type _RemoveLeadingZeros = ParseNumber extends infer WithoutLeadingZeros extends string ? IfEmptyString : never>; type _Sub = IsEmptyString extends true ? NegativeCarry extends 0 ? `${Num1}${Result}` : `${Decrement>}${Result}` : LastCharacter extends `${infer Num1LastDigit extends keyof SubMap & number}` ? LastCharacter extends `${infer Num2LastDigit extends keyof SubMap[Num1LastDigit] & number}` ? `${SubMap[Num1LastDigit][Num2LastDigit]}` extends infer DigitsSub extends keyof SubDecrementMap ? (NegativeCarry extends 1 ? Stringify : DigitsSub) extends infer DigitsSubWithCarry extends string ? Num1 extends `${infer Num1Rest}${Num1LastDigit}` ? Num2 extends `${infer Num2Rest}${Num2LastDigit}` ? DigitsSubWithCarry extends keyof SubNegativeCarryMap ? _Sub : _Sub : never : never : never : never : never : never; /** ------------------------------------------------------- * * ***Utility Type: `Sub`.*** * ------------------------------------------------------- * **Computes the subtraction of two integers at the **type level**.** * - **Behavior:** * - Handles positive and negative numbers. * - Supports numbers in the range `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * - Internally performs string-based arithmetic to handle carries/borrows. * @template Num1 - First number (minuend). * @template Num2 - Second number (subtrahend). * @example * ```ts * // Positive numbers * type Case1 = Sub<10, 2>; // ➔ 8 * * // Num1 smaller than Num2 * type Case2 = Sub<2, 10>; // ➔ -8 * * // Subtract negative number * type Case3 = Sub<2, -10>; // ➔ 12 * * // Subtract from negative number * type Case4 = Sub<-2, 10>; // ➔ -12 * * // Both negative * type Case5 = Sub<-5, -2>; // ➔ -3 * type Case6 = Sub<-2, -5>; // ➔ 3 * ``` */ type Sub = IsNegativeInteger extends true ? IsNegativeInteger extends true ? IsLowerThan extends true ? Negate<_RemoveLeadingZeros<_Sub>, Stringify>>>> : _RemoveLeadingZeros<_Sub>, Stringify>>> : Sum, Num2> extends infer Result extends number ? Negate : never : IsNegativeInteger extends true ? Sum> : IsLowerThan extends true ? Negate<_RemoveLeadingZeros<_Sub, Stringify>>> : _RemoveLeadingZeros<_Sub, Stringify>>; type SumIncrementMap = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; type SumLastDigitMap = { 10: 0; 11: 1; 12: 2; 13: 3; 14: 4; 15: 5; 16: 6; 17: 7; 18: 8; 19: 9; }; type SumMap = { 0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 2: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; 3: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; 4: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]; 5: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; 6: [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; 7: [7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 8: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; 9: [9, 10, 11, 12, 13, 14, 15, 16, 17, 18]; }; /** ------------------------------------------------------- * * ***Private Utility Type: `_Sum`.*** * ------------------------------------------------------- * **Internal helper type for summing two integer numbers represented as strings.** * - Performs digit-by-digit addition with carry handling. * @deprecated This is internal helper, use {@link Sum | **`Sum`**} instead. * @template Num1 - First number as string. * @template Num2 - Second number as string. * @template Carry - Carry flag (0 or 1), defaults to 0. * @template Result - Accumulated result string, defaults to empty string. */ type _Sum = IsEmptyString extends true ? Carry extends 0 ? ParseNumber<`${Num2}${Result}`> : _Increment : IsEmptyString extends true ? Carry extends 0 ? ParseNumber<`${Num1}${Result}`> : _Increment : LastCharacter extends `${infer Num1LastDigit extends keyof SumMap & number}` ? LastCharacter extends `${infer Num2LastDigit extends keyof SumMap[Num1LastDigit] & number}` ? SumMap[Num1LastDigit][Num2LastDigit] extends infer DigitsSum extends number ? (Carry extends 1 ? SumIncrementMap[DigitsSum] : DigitsSum) extends infer DigitsSumWithCarry extends number ? Num1 extends `${infer Num1Rest}${Num1LastDigit}` ? Num2 extends `${infer Num2Rest}${Num2LastDigit}` ? DigitsSumWithCarry extends keyof SumLastDigitMap ? _Sum : _Sum : never : never : never : never : never : never; /** ------------------------------------------------------- * * ***Utility Type: `Sum`.*** * ------------------------------------------------------- * **Adds two integers at the type level. Handles positive and negative numbers.** * - Supports numbers in the range: * - `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - First number. * @template Num2 - Second number. * @example * ```ts * // Positive + positive * type Case1 = Sum<4, 9>; // ➔ 13 * * // Negative + positive * type Case2 = Sum<-4, 9>; // ➔ 5 * * // Positive + negative * type Case3 = Sum<4, -9>; // ➔ -5 * * // Negative + negative * type Case4 = Sum<-4, -9>; // ➔ -13 * ``` */ type Sum = IsNegativeInteger extends true ? IsNegativeInteger extends true ? Negate<_Sum>, Stringify>>> : Sub> : IsNegativeInteger extends true ? Sub> : _Sum, Stringify>; type _safeSumArr = _SumArr>; type _SumArr = IsEmptyArray extends true ? CurrentSum : Pop extends infer PopResult ? IsNever extends true ? CurrentSum : PopResult extends [infer Rest extends number[], infer Num1 extends number] ? _safeSumArr : never : CurrentSum; /** ------------------------------------------------------- * * ***Utility Type: `SumArr`.*** * ------------------------------------------------------- * **Accepts a tuple of numbers and returns their sum.** * * - **Behavior:** * - Only works on tuple types (not general arrays). * - Supports numbers in the range: * - `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template T - Tuple of numbers to sum. * @example * ```ts * // Sum all elements in a tuple * type Case1 = SumArr<[1, 2, 3, 4]>; // ➔ 10 * * // Tuple with negative number * type Case2 = SumArr<[1, 2, 3, -4]>; // ➔ 2 * ``` */ type SumArr = IsTuple extends true ? _SumArr : never; type _safeSum = Sum, Sum>; type _StringLength = S extends "" ? _safeSum : S extends `${infer C1 extends string}${infer Rest1 extends string}` ? Rest1 extends `${infer C2 extends string}${infer Rest2 extends string}` ? Rest2 extends `${infer C3 extends string}${infer Rest3 extends string}` ? Rest3 extends `${infer C4 extends string}${infer Rest4 extends string}` ? _StringLength : _StringLength : _StringLength : _StringLength : _StringLength; /** ------------------------------------------------------- * * ***Utility Type: `StringLength`.*** * ------------------------------------------------------- * **Returns the length of a string at the type level.** * - Supports string length in range `[0, 3968]`. * @template S - The string to measure. * @example * ```ts * type Case1 = StringLength<''>; * // ➔ 0 * type Case2 = StringLength<'xxx'>; * // ➔ 3 * ``` */ type StringLength = _StringLength; /** ------------------------------------------------------- * * ***Utility Type: `CompareStringLength`.*** * ------------------------------------------------------- * - **Compares the lengths of two strings and returns one of three possible type values:** * - `IfStr1Shorter` if the first string is shorter. * - `IfStr2Shorter` if the second string is shorter. * - `IfEqual` if both strings have the same length. * - Defaults to `never` if not provided. * @template Str1 - First string. * @template Str2 - Second string. * @template IfStr1Shorter - Type to return if Str1 is shorter (default `never`). * @template IfStr2Shorter - Type to return if Str2 is shorter (default `never`). * @template IfEqual - Type to return if both strings have equal length (default `never`). * @example * ```ts * type Case1 = CompareStringLength<'a', 'ab', 'first shorter'>; * // ➔ 'first shorter' * type Case2 = CompareStringLength<'abc', 'ab', 'first shorter', 'first longer'>; * // ➔ 'first longer' * type Case3 = CompareStringLength<'ab', 'ab', 'first shorter', 'first longer', 'equal'>; * // ➔ 'equal' * ``` */ type CompareStringLength = IsEmptyString extends true ? IsEmptyString extends true ? IfEqual : IfStr1Shorter : IsEmptyString extends true ? IfStr2Shorter : Str1 extends `${string}${infer Str1Rest extends string}` ? Str2 extends `${string}${infer Str2Rest extends string}` ? CompareStringLength : never : never; /** ------------------------------------------------------- * * ***Utility Type: `IsShorterString`.*** * ------------------------------------------------------- * **Returns `true` if the first string is shorter than the second string; otherwise `false`.** * @template Str1 - First string. * @template Str2 - Second string. * @example * ```ts * type Case1 = IsShorterString<'a', 'ab'>; * // ➔ true * type Case2 = IsShorterString<'abc', 'ab'>; * // ➔ false * ``` */ type IsShorterString = CompareStringLength; /** ------------------------------------------------------- * * ***Utility Type: `IsLongerString`.*** * ------------------------------------------------------- * **Returns `true` if the first string is longer than the second string; otherwise `false`.** * @template Str1 - First string. * @template Str2 - Second string. * @example * ```ts * type Case1 = IsLongerString<'ab', 'a'>; // ➔ true * type Case2 = IsLongerString<'a', 'ab'>; // ➔ false * ``` */ type IsLongerString = CompareStringLength; /** ------------------------------------------------------- * * ***Utility Type: `IsSameLengthString`.*** * ------------------------------------------------------- * **Returns `true` if two strings have the same length; otherwise `false`.** * @template Str1 - First string. * @template Str2 - Second string. * @example * ```ts * type Case1 = IsSameLengthString<'ab', 'ab'>; // ➔ true * type Case2 = IsSameLengthString<'ab', 'abc'>; // ➔ false * ``` */ type IsSameLengthString = CompareStringLength; /** ------------------------------------------------------- * * ***Type Options for {@link NumberLength | **`NumberLength`**}.*** */ type TypeNumberLengthOptions = { /** * ***Removes the leading minus `-` from negative numbers, default: `true`.*** * * @default true */ stripSign?: boolean; /** * ***Removes the decimal point `.` from floats, default: `true`.*** * * @default true */ stripDot?: boolean; /** * ***Removes the trailing `n` from BigInt literals, default: `true`.*** * * @default true */ stripBigInt?: boolean; }; /** ------------------------------------------------------- * * ***Default options for {@link NumberLength | **`NumberLength`**} (all `true`).*** */ type DefaultNumberLengthOptions = { stripSign: true; stripDot: true; stripBigInt: true; }; /** ------------------------------------------------------- * * ***Merge provided options with defaults for {@link NumberLength | **`NumberLength`**}.*** */ type MergeOptions = { [K in keyof DefaultNumberLengthOptions]: K extends keyof Opts ? Opts[K] : DefaultNumberLengthOptions[K] }; /** ------------------------------------------------------- * * ***Utility Type: `NumberLength`.*** * ------------------------------------------------------- * **A type-level utility that returns the **number of digits/characters** * of a numeric literal type, with optional cleaning.** * - **Supports:** * - Integers (positive & negative). * - Floats (`.` optionally removed). * - Scientific notation (`e`/`E`, TypeScript normalizes to number). * - BigInts (`n` suffix optionally removed). * @template T - A numeric literal (`number` or `bigint`). * @template Options - Optional configuration (default: all `true`): * - `stripSign` ➔ Removes the leading `-` (default `true`). * - `stripDot` ➔ Removes the decimal point `.` (default `true`). * - `stripBigInt` ➔ Removes trailing `n` (default `true`). * @example * **✅ Valid Examples:** * ```ts * // Integers * type A = NumberLength<100>; // ➔ 3 * type B = NumberLength<-100>; // ➔ 3 (minus stripped by default) * type C = NumberLength<-100, { stripSign: false }>; // ➔ 4 (minus kept) * * // Floats * type D = NumberLength<0.25>; // ➔ 2 (dot removed) * type E = NumberLength<-0.25>; // ➔ 2 (minus & dot removed) * type F = NumberLength<12.34, { stripDot: false }>; // ➔ 5 (12.34) * * // Scientific notation * type G = NumberLength<5e4>; // ➔ 5 (50000) * type H = NumberLength<-5e4>; // ➔ 5 (-50000, minus stripped) * type I = NumberLength<-5e4,{ stripSign:false }>; // ➔ 6 (-50000, minus not stripped) * * // BigInts * type J = NumberLength<12n>; // ➔ 2 * type K = NumberLength<-2125n>; // ➔ 4 (- & n removed) * type L = NumberLength<-2125n, { stripSign: false }>; * // ➔ 5 (minus kept) * type M = NumberLength<123n, { stripBigInt: false }>; * // ➔ 4 (123n) * type N = NumberLength<-123n, { stripBigInt: false, stripSign: false }>; * // ➔ 5 (minus & n kept ➔ -123n) * ``` * --- * **❌ Invalid Examples:** * ```ts * type Invalid1 = NumberLength; // ➔ never * type Invalid2 = NumberLength; // ➔ never * type Invalid3 = NumberLength<"123">; // ➔ never (string literal) * type Invalid4 = NumberLength; // ➔ never (not literal) * type Invalid5 = NumberLength; // ➔ never (not literal) * type Invalid6 = NumberLength; // ➔ never * type Invalid7 = NumberLength; // ➔ never * type Invalid8 = NumberLength; // ➔ never * ``` * --- * @remarks * - Uses type-level string manipulation to "clean" numeric literal according to options. * - Removes `-`, `.`, or `n` if corresponding option is true. * - Works reliably for literal numbers, floats, and BigInt. * - Scientific notation is normalized by TypeScript, so `5e4` becomes `50000`. */ type NumberLength = DefaultNumberLengthOptions> = If, Extends, Not>]>> extends true ? never : StringLength, [MergeOptions["stripSign"] extends true ? "-" : "", MergeOptions["stripDot"] extends true ? "." : "", MergeOptions["stripBigInt"] extends true ? "n" : ""], "">>; /** ------------------------------------------------------- * * ***Utility Type: `CompareNumberLength`.*** * ------------------------------------------------------- * **Compares the **number of digits** of two numeric literal types.** * - **Returns:** * - `IfNum1Shorter` if the first number has fewer digits than the second (default: `never`). * - `IfNum2Shorter` if the second number has fewer digits than the first (default: `never`). * - `IfEqual` if both numbers have the same number of digits (default: `never`). * - **Important:** * - This utility only works with **literal numbers**. * - Using non-literal numbers (`number`) will return `never`. * @template Num1 - The first number literal to compare. * @template Num2 - The second number literal to compare. * @template IfNum1Shorter - Return type if the first number is shorter (default: `never`). * @template IfNum2Shorter - Return type if the second number is shorter (default: `never`). * @template IfEqual - Return type if both numbers have the same length (default: `never`). * @example * ```ts * // First number shorter than second * type Case1 = CompareNumberLength<1, 12, 'first shorter'>; * // ➔ 'first shorter' * * // First number longer than second * type Case2 = CompareNumberLength<123, 12, 'first shorter', 'first longer'>; * // ➔ 'first longer' * * // Both numbers have equal length * type Case3 = CompareNumberLength<12, 12, 'first shorter', 'first longer', 'equal'>; * // ➔ 'equal' * * // Defaults (no custom return types) * type Case4 = CompareNumberLength<1, 12>; * // ➔ never * * // Non-literal numbers * type NumA = number; * type NumB = 12; * type Case4 = CompareNumberLength; * // ➔ never * ``` * --- * @remarks * - Internally uses {@link Stringify | **`Stringify`**} and {@link CompareStringLength | **`CompareStringLength`**}. * - Works for `positive`, `negative`, and `floating-point literal numbers`. */ type CompareNumberLength = If, Extends>> extends true ? never : CompareStringLength, Stringify, IfNum1Shorter, IfNum2Shorter, IfEqual>; /** ------------------------------------------------------- * * ***Utility Type: `IsShorterNumber`.*** * ------------------------------------------------------- * **Compares the number of digits of two numeric literal types and returns a **boolean**.** * - **Returns:** * - `true` if the first number has fewer digits than the second. * - `false` otherwise (including when numbers have equal length). * - **Important:** * - This utility only works with **literal numbers**. * - Using non-literal numbers (`number`) will return `never`. * @template Num1 - The first number literal to compare. * @template Num2 - The second number literal to compare. * @example * ```ts * // Literal numbers * type Case1 = IsShorterNumber<1, 10>; * // ➔ true * * type Case2 = IsShorterNumber<100, 10>; * // ➔ false * * type Case3 = IsShorterNumber<12, 12>; * // ➔ false * * // Non-literal numbers * type NumA = number; * type NumB = 12; * type Case4 = IsShorterNumber; * // ➔ never * ``` * --- * @remarks * - Internally uses {@link CompareNumberLength | **`CompareNumberLength`**}. * - Works for `positive`, `negative`, and `floating-point literal numbers`. */ type IsShorterNumber = CompareNumberLength; /** ------------------------------------------------------- * * ***Utility Type: `IsLongerNumber`.*** * ------------------------------------------------------- * **Compares the number of digits of two numeric literal types and returns a **boolean**.** * - **Returns:** * - `true` if the first number has more digits than the second. * - `false` otherwise (including when numbers have equal length). * - **Important:** * - Only works with **literal numbers**. * - Non-literal numbers (`number`) return `never`. * @template Num1 - The first number literal to compare. * @template Num2 - The second number literal to compare. * @example * ```ts * type Case1 = IsLongerNumber<10, 1>; * // ➔ true * * type Case2 = IsLongerNumber<10, 100>; * // ➔ false * * type Case3 = IsLongerNumber<12, 12>; * // ➔ false * * // Non-literal numbers * type NumA = number; * type NumB = 12; * type Case4 = IsLongerNumber; * // ➔ never * ``` * --- * @remarks * - Internally uses {@link CompareNumberLength | **`CompareNumberLength`**}. * - Works for `positive`, `negative`, and `floating-point literal numbers`. */ type IsLongerNumber = CompareNumberLength; /** ------------------------------------------------------- * * ***Utility Type: `IsSameLengthNumber`.*** * ------------------------------------------------------- * **Compares the number of digits of two numeric literal types and returns a **boolean**.** * - **Returns:** * - `true` if the numbers have the same number of digits. * - `false` otherwise. * - **Important:** * - Only works with **literal numbers**. * - Non-literal numbers (`number`) return `never`. * @template Num1 - The first number literal to compare. * @template Num2 - The second number literal to compare. * @example * ```ts * type Case1 = IsSameLengthNumber<10, 10>; * // ➔ true * * type Case2 = IsSameLengthNumber<10, 100>; * // ➔ false * * // Non-literal numbers * type NumA = number; * type NumB = 12; * type Case3 = IsSameLengthNumber; * // ➔ never * ``` * --- * @remarks * - Internally uses {@link CompareNumberLength | **`CompareNumberLength`**}. * - Works for `positive`, `negative`, and `floating-point literal numbers`. */ type IsSameLengthNumber = CompareNumberLength; type LowerThanMap = { "0": ["1", "2", "3", "4", "5", "6", "7", "8", "9"]; "1": ["2", "3", "4", "5", "6", "7", "8", "9"]; "2": ["3", "4", "5", "6", "7", "8", "9"]; "3": ["4", "5", "6", "7", "8", "9"]; "4": ["5", "6", "7", "8", "9"]; "5": ["6", "7", "8", "9"]; "6": ["7", "8", "9"]; "7": ["8", "9"]; "8": ["9"]; "9": []; }; type _IsLowerThan = Num1 extends `${infer Num1Character extends keyof LowerThanMap}${infer Num1Rest extends string}` ? Num2 extends `${infer Num2Character extends string}${infer Num2Rest extends string}` ? IsEqual extends true ? _IsLowerThan : Num2Character extends LowerThanMap[Num1Character][number] ? true : false : true : false; /** ------------------------------------------------------- * * ***Utility Type: `IsLowerThan`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether `Num1` is strictly lower than `Num2`.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer to compare. * @template Num2 - The second integer to compare. * @example * type Case1 = IsLowerThan<1, 10>; // ➔ true * type Case2 = IsLowerThan<1, -10>; // ➔ false */ type IsLowerThan = IsEqual extends true ? false : IsNegative extends true ? IsNegative extends false ? true : CompareNumberLength>, Stringify>>>> : IsNegative extends true ? false : CompareNumberLength>, Stringify>>>; /** ------------------------------------------------------- * * ***Utility Type: `IfLowerThan`.*** * ------------------------------------------------------- * **Returns `IfTrue` if `Num1` is lower than `Num2`, otherwise returns `IfFalse`.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer to compare. * @template Num2 - The second integer to compare. * @template IfTrue - Value to return if `Num1 < Num2`. * @template IfFalse - Value to return if `Num1 >= Num2`. * @example * type Case1 = IfLowerThan<1, 10, 'valid'>; * // ➔ 'valid' * type Case2 = IfLowerThan<1, -10, 'valid', 'invalid'>; * // ➔ 'invalid' */ type IfLowerThan = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IsLowerOrEqual`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether `Num1` is lower than or equal to `Num2`.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer to compare. * @template Num2 - The second integer to compare. * @example * type Case1 = IsLowerOrEqual<1, 10>; * // ➔ true * type Case2 = IsLowerOrEqual<1, -10>; * // ➔ false */ type IsLowerOrEqual = IsEqual extends true ? true : IsLowerThan; /** ------------------------------------------------------- * * ***Utility Type: `IfLowerOrEqual`.*** * ------------------------------------------------------- * **Returns the third argument if the first argument (integer) is lower than * the second argument (integer) or equal (defaults to `true`), otherwise returns * the fourth argument (defaults to `false`).** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer to compare. * @template Num2 - The second integer to compare. * @template IfTrue - Value to return if `Num1 <= Num2`. * @template IfFalse - Value to return if `Num1 > Num2`. * @example * type Case1 = IfLowerOrEqual<1, 10, 'valid'>; * // ➔ 'valid' * type Case2 = IfLowerOrEqual<23, 1, 'valid', 'invalid'>; * // ➔ 'invalid' */ type IfLowerOrEqual = If extends true ? true : IsLowerThan, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `IsGreaterThan`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether the first integer * is ***greater than*** the second integer.** * - **Behavior:** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer. * @template Num2 - The second integer. * @example * ```ts * type A = IsGreaterThan<10, 1>; // ➔ true * type B = IsGreaterThan<-10, 1>; // ➔ false * ``` */ type IsGreaterThan = IsLowerThan; /** ------------------------------------------------------- * * ***Utility Type: `IfGreaterThan`.*** * ------------------------------------------------------- * - **Conditional:** * - Returns the third argument if the first integer is ***greater than*** the * second integer, otherwise returns the fourth argument. * - **Behavior:** * - Defaults: `IfTrue = true`, `IfFalse = false`. * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer. * @template Num2 - The second integer. * @template IfTrue - The branch type if condition is met. (default: `true`) * @template IfFalse - The branch type if condition is not met. (default: `false`) * @example * ```ts * type A = IfGreaterThan<10, 1, "valid">; * // ➔ "valid" * type B = IfGreaterThan<-10, 1, "valid", "invalid">; * // ➔ "invalid" * ``` */ type IfGreaterThan = IfLowerThan; /** ------------------------------------------------------- * * ***Utility Type: `IsGreaterOrEqual`.*** * ------------------------------------------------------- * **Returns a boolean indicating whether the first integer * is ***greater than or equal*** to the second integer.** * - **Behavior:** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer. * @template Num2 - The second integer. * @example * ```ts * type A = IsGreaterOrEqual<10, 1>; // ➔ true * type B = IsGreaterOrEqual<-10, 1>; // ➔ false * type C = IsGreaterOrEqual<10, 10>; // ➔ true * ``` */ type IsGreaterOrEqual = IsEqual extends true ? true : IsGreaterThan; /** ------------------------------------------------------- * * ***Utility Type: `IfGreaterOrEqual`.*** * ------------------------------------------------------- * - **Conditional:** * - Returns the third argument if the first integer is ***greater than or * equal*** to the second integer, otherwise returns the fourth argument. * - **Behavior:** * - Defaults: `IfTrue = true`, `IfFalse = false`. * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer. * @template Num2 - The second integer. * @template IfTrue - The branch type if condition is met. (default: `true`) * @template IfFalse - The branch type if condition is not met. (default: `false`) * @example * ```ts * type A = IfGreaterOrEqual<10, 1, "valid">; * // ➔ "valid" * type B = IfGreaterOrEqual<-10, 1, "valid", "invalid">; * // ➔ "invalid" * type C = IfGreaterOrEqual<10, 10, "yes", "no">; * // ➔ "yes" * ``` */ type IfGreaterOrEqual = If extends true ? true : IsGreaterThan, IfTrue, IfFalse>; /** --------------------------------------------------------------------------- * * ***Type Options for {@link IsBetween | `IsBetween`}.*** * --------------------------------------------------------------------------- * **Options to configure whether the borders of the interval are included * when using {@link IsBetween | **`IsBetween`**}.** */ type IsBetweenOptions = { /** * ***Whether to include the lower border (`Min`) in the comparison.*** * * - `true` ➔ include `Min` (**default**). * - `false` ➔ exclude `Min`. * * @default true */ minIncluded?: boolean; /** * ***Whether to include the upper border (`Max`) in the comparison.*** * * - `true` ➔ include `Max` (**default**). * - `false` ➔ exclude `Max`. * * @default true */ maxIncluded?: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `IsBetween`.*** * ------------------------------------------------------- * **Returns a boolean whether the first integer argument is between the second and the third integer argument, by default, borders of the interval are included, which can be modified by the second argument.** * - **Behavior:** * - `minIncluded`, `maxIncluded` options show whether to include the lower and the higher borders * respectively. * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @example * type Case1 = IsBetween<1, 1, 10>; * // ➔ true * type Case2 = IsBetween<1, 1, 10, {minIncluded: false}>; * // ➔ false * type Case3 = IsBetween<10, 1, 10, {maxIncluded: false}>; * // ➔ false */ type IsBetween = IsEqual extends true ? Options["minIncluded"] : IsEqual extends true ? Options["maxIncluded"] : And, IsLowerThan>; type _IsValidRGBParameter = IsInteger extends true ? IsBetween : false; /** * ***Configuration options for a type-level utility * {@link RGB | `RGB`} | {@link IsRGB | `IsRGB` } | {@link IfRGB | `IfRGB` }.*** */ type RGBOptions = { /** * ***Separator character(s) used between the RGB components (`r`, `g`, `b`).*** * * - **For example:** * - `","` ➔ `"rgb(23,242,0)"`. * - `", "` ➔ `"rgb(23, 242, 0)"`. * * @default ", " */ separator: string; }; /** * ***Default configuration for the {@link RGBOptions | `RGBOptions`}.*** * * @example * ```ts * type Opt = DefaultRGBOptions; * // ➔ { separator: ", " } * ``` */ type DefaultRGBOptions = { /** * ***Default separator for RGB components.*** * * **Produces strings like `"rgb(23, 242, 0)"`.** */ separator: ", "; }; /** ------------------------------------------------------- * * ***Utility Type: `RGB`.*** * ------------------------------------------------------- * **A type-level utility that validates an **RGB color string**.** * - **Behavior:** * - Accepts `rgb(r, g, b)` format with customizable separators. * - Each parameter `r`, `g`, `b` must be an integer between `0` and `255`. * - Returns `T` if valid, otherwise `never`. * @template T - A string to check. * @template Options - Options with `separator` (defaults to `", "`). * @example * ```ts * type A = RGB<"rgb(23, 242, 0)">; * // ➔ "rgb(23, 242, 0)" * type B = RGB<"rgb(324, 123, 3)">; * // ➔ never * type C = RGB<"rgb(23,242,0)", { separator: "," }>; * // ➔ "rgb(23,242,0)" * ``` */ type RGB = T extends `rgb(${infer R extends number}${Options["separator"]}${infer G extends number}${Options["separator"]}${infer B extends number})` ? AndArr<[_IsValidRGBParameter, _IsValidRGBParameter, _IsValidRGBParameter]> extends true ? T : never : never; /** ------------------------------------------------------- * * ***Utility Type: `IsRGB`.*** * ------------------------------------------------------- * **A type-level utility that checks if a string is a valid **RGB color**.** * - Returns `true` if valid, otherwise `false`. * @template T - A string to check. * @template Options - Options with `separator` (defaults to `", "`). * @example * ```ts * type A = IsRGB<"rgb(23, 242, 0)">; * // ➔ true * type B = IsRGB<"rgb(324, 123, 3)">; * // ➔ false * type C = IsRGB<"rgb(23,242,0)", { separator: "," }>; * // ➔ true * ``` */ type IsRGB = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IfRGB`.*** * ------------------------------------------------------- * **A conditional type that returns `IfTrue` if `T` is a valid **RGB color**, * otherwise returns `IfFalse`.** * @template T - A string to check. * @template IfTrue - Return type if valid (defaults to `true`). * @template IfFalse - Return type if invalid (defaults to `false`). * @template Options - Options with `separator` (defaults to `", "`). * @example * ```ts * type A = IfRGB<"rgb(23, 242, 0)">; * // ➔ true * type B = IfRGB<"rgb(23, 242, 0)", "valid">; * // ➔ "valid" * type C = IfRGB<"rgb(324, 123, 3)", "valid", "invalid">; * // ➔ "invalid" * type D = IfRGB<"rgb(23,242,0)", true, false { separator: "," }>; * // ➔ true * ``` */ type IfRGB = If, IfTrue, IfFalse>; type _ValidHEXCharacters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]; type _AllowedHEXLength = 3 | 4 | 6 | 8; /** ------------------------------------------------------- * * ***Utility Type: `HEX`.*** * ------------------------------------------------------- * **A type-level utility that validates a **HEX color string**.** * - **Behavior:** * - Accepts `#RGB`, `#RGBA`, `#RRGGBB`, or `#RRGGBBAA` formats. * - Characters must be `[0-9A-F]` (**case-insensitive**). * - Returns `T` if valid, otherwise `never`. * @template T - A string to check. * @example * ```ts * type A = HEX<"#000">; // ➔ "#000" * type B = HEX<"#g00">; // ➔ never * type C = HEX<"#0000">; // ➔ "#0000" * type D = HEX<"#00000">; // ➔ never * type E = HEX<"#000000">; // ➔ "#000000" * type F = HEX<"#00000000">; // ➔ "#00000000" * ``` */ type HEX = (Uppercase extends `#${infer HEXWithoutHashTag extends string}` ? StringLength extends _AllowedHEXLength ? ExtendsArr, _ValidHEXCharacters[number]> : false : false) extends true ? T : never; /** ------------------------------------------------------- * * ***Utility Type: `IsHEX`.*** * ------------------------------------------------------- * **A type-level utility that checks if a string is a valid **HEX color**.** * - Returns `true` if valid, otherwise `false`. * @template T - A string to check. * @example * ```ts * type A = IsHEX<"#000">; // ➔ true * type B = IsHEX<"#g00">; // ➔ false * ``` */ type IsHEX = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IfHEX`.*** * ------------------------------------------------------- * **A conditional type that returns `IfTrue` if `T` is a valid **HEX color**, * otherwise returns `IfFalse`.** * @template T - A string to check. * @template IfTrue - Return type if valid (defaults to `true`). * @template IfFalse - Return type if invalid (defaults to `false`). * @example * ```ts * type A = IfHEX<"#000">; * // ➔ true * type B = IfHEX<"#g00">; * // ➔ false * type C = IfHEX<"#0000", "valid">; * // ➔ "valid" * type D = IfHEX<"#00000", "valid","invalid">; * // ➔ "invalid" * ``` */ type IfHEX = If, IfTrue, IfFalse>; /** * ***Configuration options for a type-level utility * {@link HSL | `HSL` } | {@link IsHSL | `IsHSL` } | {@link IfHSL | `IfHSL` }.*** */ type HSLOptions = { /** * ***Separator character(s) used between the HSL components (`h`, `s`, `l`).*** * * - **For example:** * - `","` ➔ `"hsl(180,100%,50%)"`. * - `", "` ➔ `"hsl(180, 100%, 50%)"`. * * @default ", " */ separator: string; }; /** * ***Default configuration for the {@link HSLOptions | `HSLOptions`}.*** * * @example * ```ts * type Opt = DefaultHSLOptions; * // ➔ { separator: ", " } * ``` */ type DefaultHSLOptions = { /** * ***Default separator for HSL components.*** * * **Produces strings like `"hsl(180, 100%, 50%)"`.** */ separator: ", "; }; /** ------------------------------------------------------- * * ***Utility Type: `HSL`.*** * ------------------------------------------------------- * **A type-level utility that validates an **HSL color string**.** * - **Behavior:** * - Accepts `hsl(h, s%, l%)` format with customizable separators. * - `h` must be an integer, `s` and `l` must be integers between `0` and `100`. * - Returns `T` if valid, otherwise `never`. * @template T - A string to check. * @template Options - Options with `separator` (defaults to `", "`). * @example * ```ts * type A = HSL<"hsl(100, 34%, 56%)">; * // ➔ "hsl(100, 34%, 56%)" * type B = HSL<"hsl(100, 200%, 3)">; * // ➔ never * type C = HSL<"hsl(100,34%,56%)", { separator: "," }>; * // ➔ "hsl(100,34%,56%)" * ``` */ type HSL = (T extends `hsl(${infer H extends number}${Options["separator"]}${infer S extends number}%${Options["separator"]}${infer L extends number}%)` ? AndArr<[IsInteger, IsInteger, IsInteger]> extends true ? AndArr<[IsBetween, IsBetween]> : false : false) extends true ? T : never; /** ------------------------------------------------------- * * ***Utility Type: `IsHSL`.*** * ------------------------------------------------------- * **A type-level utility that checks if a string is a valid **HSL color**.** * - Returns `true` if valid, otherwise `false`. * @template T - A string to check. * @template Options - Options with `separator` (defaults to `", "`). * @example * ```ts * type A = IsHSL<"hsl(100, 34%, 56%)">; * // ➔ true * type B = IsHSL<"hsl(101, 200%, 3)">; * // ➔ false * type C = IsHSL<"hsl(100,34%,56%)", { separator: "," }>; * // ➔ true * ``` */ type IsHSL = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IfHSL`.*** * ------------------------------------------------------- * **A conditional type that returns `IfTrue` if `T` is a valid **HSL color**, * otherwise returns `IfFalse`.** * @template T - A string to check. * @template IfTrue - Return type if valid (defaults to `true`). * @template IfFalse - Return type if invalid (defaults to `false`). * @template Options - Options with `separator` (defaults to `", "`). * @example * ```ts * type A = IfHSL<"hsl(100, 34%, 56%)", "ok">; * // ➔ "ok" * type B = IfHSL<"hsl(101, 200%, 3)", "ok", "fail">; * // ➔ "fail" * type C = IfHSL<"hsl(100,34%,56%)", true, false, { separator: "," }>; * // ➔ true * ``` */ type IfHSL = If, IfTrue, IfFalse>; /** * ***High-level configuration for {@link Color | `Color`} parsing utilities.*** * * **Allows customizing **RGB** and **HSL** parsing behavior independently.** */ type ColorOptions = { /** * ***Options for handling RGB color strings.*** * * - **Behavior:** * - Controls parsing and formatting behavior of RGB values. * - By default uses {@link DefaultRGBOptions | **`DefaultRGBOptions`**}. * @default DefaultRGBOptions * @example * ```ts * type Opt = ColorOptions["rgbOptions"]; * // ➔ { separator: string } * * // with defaults applied: * type Opt = DefaultRGBOptions; * // ➔ { separator: ", " } * ``` */ rgbOptions?: RGBOptions; /** * ***Options for handling HSL color strings.*** * * - **Behavior:** * - Controls parsing and formatting behavior of HSL values. * - By default uses {@link DefaultHSLOptions | **`DefaultHSLOptions`**}. * @default DefaultHSLOptions * @example * ```ts * type Opt = ColorOptions["hslOptions"]; * // ➔ { separator: string } * * // with defaults applied: * type Opt = DefaultHSLOptions; * // ➔ { separator: ", " } * ``` */ hslOptions?: HSLOptions; }; /** * ***Default configuration for the {@link ColorOptions |`ColorOptions`}.*** * * @example * ```ts * type Opt = DefaultColorOptions; * // ➔ { rgbOptions: { separator: ", " }, hslOptions: { separator: ", " } } * ``` */ type DefaultColorOptions = { /** * ***Default configuration for `RGBOptions`.*** * * - **Behavior:** * - Provides the default separator for RGB strings. * - By default: `", "` * @example * ```ts * type RGBOpt = DefaultColorOptions["rgbOptions"]; * // ➔ { separator: ", " } * ``` */ rgbOptions: DefaultRGBOptions; /** * ***Default configuration for `HSLOptions`.*** * * - **Behavior:** * - Provides the default separator for HSL strings. * - By default: `", "` * @example * ```ts * type HSLOpt = DefaultColorOptions["hslOptions"]; * // ➔ { separator: ", " } * ``` */ hslOptions: DefaultHSLOptions; }; type ResolveRGBOptions = O["rgbOptions"] extends RGBOptions ? O["rgbOptions"] : DefaultRGBOptions; type ResolveHSLOptions = O["hslOptions"] extends HSLOptions ? O["hslOptions"] : DefaultHSLOptions; /** ------------------------------------------------------- * * ***Utility Type: `Color`.*** * ------------------------------------------------------- * - **A type-level utility that validates a string as a **Color** in:** * - **`RGB`**. * - **`HEX`**. * - **`HSL`**. * @returns {T} Returns `T` if valid, otherwise `never`. * @template T - A string to check. * @template Options - Options to pass down to `RGB`/`HSL` validation. * @example * ```ts * type A = Color<"rgb(23, 242, 0)">; * // ➔ "rgb(23, 242, 0)" * type B = Color<"rgb(324, 123, 3)">; * // ➔ never * type C = Color<"#000000">; * // ➔ "#000000" * type D = Color<"hsl(100,34%,56%)", { hslOptions: { separator: "," }}>; * // ➔ "hsl(100,34%,56%)" * ``` */ type Color = HEX | HSL> | RGB>; /** ------------------------------------------------------- * * ***Utility Type: `IsColor`.*** * ------------------------------------------------------- * **A type-level utility that checks if a string is a valid **Color** * (`RGB` | `HEX` | `HSL`).** * @returns {T} - Returns `true` if valid, otherwise `false`. * @template T - A string to check. * @template Options - Options to pass down to RGB/HSL validation. * @example * ```ts * type A = IsColor<"rgb(23, 242, 0)">; * // ➔ true * type B = IsColor<"rgb(324, 123, 3)">; * // ➔ false * type C = IsColor<"#000000">; * // ➔ true * type D = IsColor<"hsl(100,34%,56%)", { hslOptions: { separator: "," } }>; * // ➔ true * ``` */ type IsColor = Not>>; /** ------------------------------------------------------- * * ***Utility Type: `IfColor`.*** * ------------------------------------------------------- * **A conditional type that returns `IfTrue` if `T` is a valid **Color** * (`RGB` | `HEX` | `HSL`), otherwise returns `IfFalse`.** * @template T - A string to check. * @template IfTrue - Return type if valid (defaults to `true`). * @template IfFalse - Return type if invalid (defaults to `false`). * @template Options - Options to pass down to RGB/HSL validation. * @example * ```ts * type A = IfColor<"rgb(23, 242, 0)", { rgbOptions: { separator: ", " }}, "valid">; * // ➔ "valid" * type B = IfColor<"rgb(324, 123, 3)", DefaultColorOptions, "valid","invalid">; * // ➔ "invalid" * type C = IfColor<"#000000">; * // ➔ true * ``` */ type IfColor = If, IfTrue, IfFalse>; /** ------------------------------------------------------- * * ***Utility Type: `Concat`.*** * ------------------------------------------------------- * **A type-level utility that concatenates `two arrays` into `one`.** * @template T - The first array type. * @template U - The second array type, or a single element. * @example * ```ts * type A = Concat<[number, number], [string, string]>; * // ➔ [number, number, string, string] * type B = Concat<[], [1, 2]>; * // ➔ [1, 2] * type C = Concat<[1, 2], 3>; * // ➔ [1, 2, 3] * type D = Concat<[], 5>; * // ➔ [5] * type E = Concat<[1, 2], []>; * // ➔ [1, 2] * ``` */ type Concat = [...T, ...(U extends readonly unknown[] ? U : [U])]; /** ------------------------------------------------------- * * ***Utility Type: `DigitsTuple`.*** * ------------------------------------------------------- * **A **type-level utility** that converts a numeric literal (number or bigint) into * a structured representation of its digits.** * - **The resulting type is an **object** with the following properties:** * - `negative`: boolean flag indicating if the number is negative. * - `bigint`: boolean flag indicating if the value is a bigint. * - `float`: boolean flag indicating if the value is a floating-point number. * - `digits`: a tuple of digits (each as a `number`), with decimal points and * bigint suffix `n` removed. * - **Works with:** * - Positive integers * - Negative integers * - Zero and negative zero * - Floating-point numbers (decimal points are ignored) * - BigInt values * **Note:** TypeScript automatically normalizes scientific notation numeric literals * (e.g., `5e3` ➔ `5000`), so the `digits` tuple will reflect the expanded value. * @template T - A numeric literal type (`number` or `bigint`) to convert. * @example * ```ts * // Single digit * type A = DigitsTuple<1>; * // ➔ { negative: false; bigint: false; float: false; digits: [1] } * * // Positive integer * type B = DigitsTuple<123>; * // ➔ { negative: false; bigint: false; float: false; digits: [1, 2, 3] } * * // Negative integer * type C = DigitsTuple<-123>; * // ➔ { negative: true; bigint: false; float: false; digits: [1, 2, 3] } * * // Zero and negative zero (treated the same) * type D = DigitsTuple<0>; * // ➔ { negative: false; bigint: false; float: false; digits: [0] } * type E = DigitsTuple<-0>; * // ➔ { negative: false; bigint: false; float: false; digits: [0] } * * // Floating-point numbers * type F = DigitsTuple<0.123>; * // ➔ { negative: false; bigint: false; float: true; digits: [0, 1, 2, 3] } * type G = DigitsTuple<-0.123>; * // ➔ { negative: true; bigint: false; float: true; digits: [0, 1, 2, 3] } * * // BigInt values * type H = DigitsTuple<98765n>; * // ➔ { negative: false; bigint: true; float: false; digits: [9, 8, 7, 6, 5] } * type I = DigitsTuple<-98765n>; * // ➔ { negative: true; bigint: true; float: false; digits: [9, 8, 7, 6, 5] } * * // Scientific notation numeric literals (auto-expanded) * type J = DigitsTuple<5e3>; // `5e3` is same like `5000` * // ➔ { negative: false; bigint: false; float: false; digits: [5, 0, 0, 0] } * type K = DigitsTuple<-2.5e2>; // `-2.5e2` is same like `-250` * // ➔ { negative: true; bigint: false; float: true; digits: [2, 5, 0] } * ``` */ type DigitsTuple = { negative: `${T}` extends `-${string}` ? true : false; float: IsFloat> extends true ? true : false; bigint: T extends bigint ? true : false; digits: Split>, [".", "n"], "">> extends infer R ? { [K in keyof R]: R[K] extends string ? ParseNumber : never } : never; }; /** ------------------------------------------------------- * * ***Utility Type: `ReturnItselfIfExtends`.*** * ------------------------------------------------------- * **This utility is useful when you want to **narrow types by extension**, * replacing them with a fallback if they match a given base constraint, * while preserving them otherwise.** * - **A conditional type that returns:** * - `Else` if `T` extends `Base`. * - `T` itself if `T` does extend `Base`. * - `IfANever` if `T` is `never`. * @template T - The type to check. * @template Base - The base type to test against. * @template Else - The type to return if `T` extends `Base`. * @template IfANever - The type to return if `T` or `Base` is `never` (default: `never`). * @example * ```ts * type Case1 = ReturnItselfIfExtends<1, number, 2> * // ➔ 1 * * type Case2 = ReturnItselfIfExtends<'1', number, 2> * // ➔ 2 * * // ℹ️ Never Case: * type Case3 = ReturnItselfIfExtends * // ➔ never * * type Case4 = ReturnItselfIfExtends * // ➔ undefined * ``` */ type ReturnItselfIfExtends = IfNever, true>, never>, IfANever, T extends Base ? T : Else>; /** ------------------------------------------------------- * * ***Utility Type: `ReturnItselfIfNotExtends`.*** * ------------------------------------------------------- * **This utility is useful for preserving a type unless it matches * a broader constraint, in which case it is replaced with a fallback.** * - **A conditional type that returns:** * - `Else` if `T` extends `Base`. * - `T` itself if `T` does **not** extend `Base`. * - `IfANever` if `T` is `never`. * @template T - The type to check. * @template Base - The base type to test against. * @template Else - The type to return if `T` extends `Base`. * @template IfANever - The type to return if `T` or `Base` is `never` (default: `never`). * @example * ```ts * type Case1 = ReturnItselfIfNotExtends<'1', number, 2> * // ➔ '1' * type Case2 = ReturnItselfIfNotExtends<1, number, 2> * // ➔ 2 * * // ℹ️ Never Case: * type Case3 = ReturnItselfIfNotExtends; * // ➔ never * type Case4 = ReturnItselfIfNotExtends; * // ➔ undefined * ``` */ type ReturnItselfIfNotExtends = IfNever, true>, never>, IfANever, T extends Base ? Else : T>; type MultiplicationMap = { 0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 2: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]; 3: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]; 4: [0, 4, 8, 12, 16, 20, 24, 28, 32, 36]; 5: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]; 6: [0, 6, 12, 18, 24, 30, 36, 42, 48, 54]; 7: [0, 7, 14, 21, 28, 35, 42, 49, 56, 63]; 8: [0, 8, 16, 24, 32, 40, 48, 56, 64, 72]; 9: [0, 9, 18, 27, 36, 45, 54, 63, 72, 81]; }; type _MultiSingle = IsEmptyString extends true ? ReturnItselfIfNotExtends, "", "0"> : IsEqual extends true ? "0" : IsEqual extends true ? "0" : LastCharacter extends [infer Num1LastCharacter extends string, infer Num1Rest extends string] ? Stringify & keyof MultiplicationMap[DigitOfNum2]], Carry>> extends infer Multiplied extends string ? LastCharacter extends [infer MultipliedLastDigit extends string, infer MultipliedRest extends string] ? _MultiSingle>, 0, ParseNumber>, `${MultipliedLastDigit}${Result}`> : never : never : never; type _Multi = IsEmptyString extends true ? Result : LastCharacter extends [infer Num2LastCharacter extends string, infer Num2Rest extends string] ? ParseNumber extends infer Num2Digit extends keyof MultiplicationMap ? _Multi}${Repeat<"0", Iteration["length"]>}`, "0">, "", "0">>>, Push> : never : Result; /** ------------------------------------------------------- * * ***Utility Type: `Multi`.*** * ------------------------------------------------------- * **Accepts two integers and returns their **multiplication**.** * - **Behavior:** * - Handles negative numbers automatically. * - Uses internal type-level recursion to simulate multiplication of * digit strings. * - Works with integers within the range: * - `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - The first integer (can be negative). * @template Num2 - The second integer (can be negative). * @example * ```ts * type Case1 = Multi<10, 0>; // ➔ 0 * type Case2 = Multi<4, 6>; // ➔ 24 * type Case3 = Multi<-4, 6>; // ➔ -24 * type Case4 = Multi<-4, -6>; // ➔ 24 * type Case5 = Multi<123, 45>; // ➔ 5535 * ``` * @note * - ***Internal helpers:*** * - `_Multi` ➔ Recursively multiplies digit strings and accumulates the result. * - `_MultiSingle` ➔ Multiplies a string-number with a single digit, handling carry. */ type Multi = IsEqual extends true ? 0 : IsEqual extends true ? 0 : ParseNumber<_Multi>, Stringify>>> extends infer Result extends number ? IfNegative>, IfNegative, Result>> : never; type _FindQuotient = Multi extends infer Product extends number ? IsEqual extends true ? CurrentQuotient : IsLowerThan extends true ? _FindQuotient> : CurrentQuotient : never; type _Div = Or, IsLowerThan, Divisor>> extends true ? IsEmptyString extends true ? ParseNumber>, `${Result}0`, Result>> : Dividend extends `${infer FirstDigit extends string}${infer Rest extends string}` ? _Div>, `${Result}0`, Result>, IfEqual, Increment, HadFirstDivision> : never : _FindQuotient, Divisor, 10> extends infer Quotient extends number ? IsNever extends true ? ParseNumber : Sub, Multi> extends infer Remainder extends number ? _Div, 0, true> : never : never; /** ------------------------------------------------------- * * ***Utility Type: `Div`.*** * ------------------------------------------------------- * **A type-level utility that returns the integer division of two numbers. * Handles negative numbers correctly and returns `never` if dividing by zero.** * - **Behavior:** * - Returns `0` if the absolute value of dividend is smaller than divisor. * - Preserves the sign according to standard integer division rules. * @template Dividend - The dividend number. * @template Divisor - The divisor number. * @example * ```ts * type A = Div<10, 2>; // ➔ 5 * type B = Div<7, 3>; // ➔ 2 * type C = Div<-7, 3>; // ➔ -2 * type D = Div<7, -3>; // ➔ -2 * type E = Div<-7, -3>; // ➔ 2 * type F = Div<2, 5>; // ➔ 0 * type G = Div<0, 5>; // ➔ 0 * type H = Div<5, 0>; // ➔ never * ``` */ type Div = IsEqual extends true ? never : IsEqual extends true ? 0 : IsEqual extends true ? 1 : IsLowerThan, Abs> extends true ? 0 : _Div>, Abs> extends infer Quotient extends number ? If, IsNegative>, And, IsPositive>>, Quotient, Negate> : never; /** ------------------------------------------------------- * * ***Utility Type: `Dot`.*** * ------------------------------------------------------- * **A type-level utility that concatenates two string literals with a `.`.** * - **Behavior:** * - If the `Trims` flag is `true` (default), leading and trailing spaces in * both strings are trimmed before concatenation. * - If the second string literal is empty, it returns the first string literal. * - If the first string literal is empty, it returns the second string literal. * - Otherwise, it returns `${T}.${U}` (trimmed if `Trims` is `true`). * @template T - The first string literal. * @template U - The second string literal. * @template Trims - Whether to trim whitespace from the inputs before concatenation (default: `true`). * @example * ```ts * type A = Dot<"foo", "bar">; * // ➔ "foo.bar" * type B = Dot<"foo", "">; * // ➔ "foo" * type C = Dot<"", "baz">; * // ➔ "baz" * type D = Dot<" hello ", " world ", true>; * // ➔ "hello.world" * type E = Dot<" hello ", " world ", false>; * // ➔ " hello . world " * ``` */ type Dot = Extends extends true ? "" extends Trim ? Trim : "" extends Trim ? `${Trim}` : `${Trim}.${Trim}` : "" extends U ? T : `${T}.${U}`; /** ------------------------------------------------------- * * ***Utility Type: `DotArray`.*** * ------------------------------------------------------- * **A type-level utility that concatenates an array of string literals with a `.`.** * - **Behavior:** * - Skips empty strings in the array. * - If `Trims` is `true` (default), trims whitespace from each element. * - Returns a single string literal. * @template Arr - An array of string literals. * @template Trims - Whether to trim whitespace from each element (default: `true`). * @example * ```ts * type A = DotArray<["foo", "bar", "baz"]>; * // ➔ "foo.bar.baz" * type B = DotArray<["foo", "", "baz"]>; * // ➔ "foo.baz" * type C = DotArray<[" foo ", " bar "], true>; * // ➔ "foo.bar" * type D = DotArray<[" foo ", " bar "], false>; * // ➔ " foo . bar " * type E = DotArray<[]>; * // ➔ "" * ``` */ type DotArray = Arr extends [infer Head extends string, ...infer Tail extends string[]] ? Head extends "" ? DotArray : `${Trims extends true ? Trim : Head}${Tail extends [] ? "" : `.${DotArray}`}` : ""; /** ------------------------------------------------------- * * ***Utility Type: `EndsWith`.*** * ------------------------------------------------------- * **A type-level utility that returns a boolean indicating * whether the first string literal ends with the ***second one***.** * @template T - The string to check. * @template C - The ***ending string*** to match. * @example * ```ts * type A = EndsWith<"Hello", "lo">; // ➔ true * type B = EndsWith<"Foobar", "bar">; // ➔ true * type C = EndsWith<"Foobar", "foo">; // ➔ false * type D = EndsWith<"Hello", "world">; // ➔ false * ``` */ type EndsWith = T extends `${infer _}${C}` ? true : false; /** -------------------------------------------------- * * ***Utility Type: `ExcludeStrict`.*** * -------------------------------------------------- * **Performs a stricter version of `Exclude` with improved type narrowing.** * - ✅ Especially useful in generic libraries or utility types * where standard `Exclude` may collapse or widen types unintentionally. * @template T - The full union or set of types. * @template U - The type(s) to be excluded from `T`. * @example * ```ts * type A = 'a' | 'b' | 'c'; * type B = ExcludeStrict; * // ➔ 'a' | 'c' * ``` */ type ExcludeStrict = T extends unknown ? 0 extends (U extends T ? ([T] extends [U] ? 0 : never) : never) ? never : T : never; /** -------------------------------------------------- * * ***Utility Type: `ExtractStrict`.*** * -------------------------------------------------- * **Performs a stricter version of the built-in `Extract` * with improved type narrowing.** * - ✅ Especially useful in generic utilities where the * standard `Extract` can widen or collapse unions. * @template T - The full union or set of types. * @template U - The type(s) to be kept from `T`. * @example * ```ts * type A = 'a' | 'b' | 'c'; * type B = ExtractStrict; * // ➔ 'b' | 'c' * ``` */ type ExtractStrict = T extends unknown ? 0 extends (U extends T ? ([T] extends [U] ? 0 : never) : never) ? T : never : never; type _Factorial = IsEqual extends true ? Multi : _Factorial, Multi>; /** ------------------------------------------------------- * * ***Utility Type: `Factorial`.*** * ------------------------------------------------------- * **Accepts an integer argument and returns its ***mathematical factorial***.** * - **Behavior:** * - Valid range: `[0, 21]`. * - Negative numbers or `number` type result in `never`. * @template T - The integer to compute factorial for. * @example * ```ts * type A = Factorial<0>; * // ➔ 1 * type B = Factorial<6>; * // ➔ 720 * type C = Factorial<-5>; * // ➔ never * type D = Factorial; * // ➔ never * ``` */ type Factorial = number extends T ? never : IsNegative extends true ? never : IsEqual extends true ? 1 : _Factorial; /** ------------------------------------------------------- * * ***Utility Type: `Fibonacci`.*** * ------------------------------------------------------- * **A type-level utility that computes the ***Fibonacci number*** at a given * index `T`.** * - **Behavior:** * - Returns `never` for negative numbers. * - Supports indices in the range `[0, 78]` due to TypeScript recursion limits. * @template T - The index of the Fibonacci sequence. * @example * ```ts * type A = Fibonacci<0>; // ➔ 0 * type B = Fibonacci<1>; // ➔ 1 * type C = Fibonacci<4>; // ➔ 3 * type D = Fibonacci<10>; // ➔ 55 * type E = Fibonacci<40>; // ➔ 102334155 * type D = Fibonacci; // ➔ never * ``` */ type Fibonacci = IsNegative extends true ? never : IsLowerThan extends true ? T : Fibonacci> extends infer NMinusOne extends number ? Fibonacci> extends infer NMinusTwo extends number ? Sum : never : never; /** --------------------------------------------------------------------------- * * ***Type Options for {@link FirstCharacter | `FirstCharacter`}.*** * --------------------------------------------------------------------------- * **Configuration options for the {@link FirstCharacter | `FirstCharacter`} type-level utility.** */ type FirstCharacterOptions = { /** * ***Whether to include the rest of the string in the result tuple.*** * * - **Behavior:** * - `true` ➔ returns `[first character, rest of string]`. * - `false` ➔ returns only the first character. * @default false * @example * ```ts * type Opt = { includeRest: true }; * type R = FirstCharacter<"abc", Opt>; // ➔ ["a", "bc"] * ``` */ includeRest: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `FirstCharacter`.*** * ------------------------------------------------------- * **Accepts a string literal and returns its first character.** * - **Behavior:** * - If `Options["includeRest"]` is `true`, it returns a * tuple: `[first character, rest of string]`. * - Otherwise, it returns only the first character. * @template T - The string literal to process. * @template Options - Configuration options (default: `{ includeRest: false }`). * - `includeRest: boolean` — Whether to include the rest of the string in a tuple. * @example * ```ts * type A = FirstCharacter<"abc">; * // ➔ "a" * type B = FirstCharacter<"abc", { includeRest: true }>; * // ➔ ["a", "bc"] * type C = FirstCharacter<"">; * // ➔ never * type D = FirstCharacter; * // ➔ never * ``` */ type FirstCharacter = T extends `${infer First extends string}${infer Rest extends string}` ? If : never; /** ------------------------------------------------------- * * ***Utility Type: `FirstDigit`.*** * ------------------------------------------------------- * **Extracts the **first digit** of a given number `T`.** * - **Behavior:** * - Works with integers and decimals. * - Handles negative numbers (`-123` ➔ `-1`). * - Handles `0` and `-0` correctly (always returns `0`). * - Works with bigint literals too. * @template T - A number or bigint to extract the first digit from. * @template Options - Optional settings. * - `alwaysPositive?: boolean` (default: `false`) * If `true`, the result is always positive regardless of the sign. * @example * ```ts * type A = FirstDigit<0>; // ➔ 0 * type B = FirstDigit<-0>; // ➔ 0 * type C = FirstDigit<123>; // ➔ 1 * type D = FirstDigit<-123>; // ➔ -1 * type E = FirstDigit<0.123>; // ➔ 0 * type F = FirstDigit<-0.123>; // ➔ 0 * type G = FirstDigit<98765>; // ➔ 9 * type H = FirstDigit<-98765>; // ➔ -9 * type I = FirstDigit<-98765, {alwaysPositive:true}>; // ➔ 9 * ``` */ type FirstDigit$1; * // ➔ 9 * * @default false */ alwaysPositive?: boolean; } = { alwaysPositive: false; }> = DigitsTuple["digits"] extends readonly [infer First extends number, ...unknown[]] ? Options["alwaysPositive"] extends true ? First : DigitsTuple["negative"] extends true ? Negate : First : never; /** ------------------------------------------------------- * * ***Utility Type: `Floor`.*** * ------------------------------------------------------- * **Type-level equivalent of `Math.floor()`.** * - Returns the ***floored value*** of the passed number. * @template T - A number type. * @example * ```ts * type A = Floor<1.9>; // ➔ 1 * type B = Floor<-1.2>; // ➔ -2 * type C = Floor<3>; // ➔ 3 * type D = Floor<-5>; // ➔ -5 * ``` */ type Floor = IsFloat extends true ? GetFloatNumberParts extends [infer Whole extends number, unknown] ? IsNegative extends true ? Negate> : Whole : never : T; /** -------------------------------------------------- * * ***Utility Type: `Identity`.*** * -------------------------------------------------- * **Identity utility type that preserves the structure and inference of type `T`.** * - ✅ Commonly used to force TypeScript to expand a mapped or intersection type * into a more readable and usable shape. * @template T - The type to preserve and normalize. * @example * ```ts * type A = { a: string; b: number }; * type B = Identity; * // ➔ { a: string; b: number } * ``` */ type Identity = { [P in keyof T]: T[P] }; /** --------------------------------------------------------------------------- * * ***Type Options for {@link Shift | `Shift`}.*** * --------------------------------------------------------------------------- */ type ShiftOptions = { /** * If `true`, return both the rest of the array and the removed element * as a tuple `[Rest, Removed]`. * * Default is `false`. * * @default false */ includeRemoved: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `Shift`.*** * ------------------------------------------------------- * **Removes the first element from the array type `T`.** * - **Behavior:** * - By default (`includeRemoved: false`), returns the array without the first element. * - If `includeRemoved: true`, returns a tuple `[Rest, Removed]`: * - `Rest`: the remaining array. * - `Removed`: the removed first element. * @template T - The array type to operate on. * @template Options - Optional flags. Default `{ includeRemoved: false }`. * @example * ```ts * // Default: just remove first element * type Case1 = Shift<[1, 2, 3]>; * // ➔ [2, 3] * * // Include removed element * type Case2 = Shift<[1, 2, 3], { includeRemoved: true }>; * // ➔ [[2, 3], 1] * * // Empty array * type Case3 = Shift<[]>; * // ➔ never * ``` */ type Shift = T extends readonly [infer Removed, ...infer Rest extends readonly unknown[]] ? If : never; /** ------------------------------------------------------- * * ***Utility Type: `Includes`.*** * ------------------------------------------------------- * **Returns a boolean whether the second argument is in the first array argument.** * @template T - The array to check. * @template Pivot - The value to look for. * @example * ```ts * type Case1 = Includes<[1, 2, 3], 1>; // ➔ true * type Case2 = Includes<[1, 2, 3], 4>; // ➔ false * ``` */ type Includes = IsEmptyArray extends true ? false : Shift extends [infer Rest extends readonly unknown[], infer Removed] ? IfEqual> : false; type _IndexOfArray = T extends readonly [infer First, ...infer Rest extends unknown[]] ? IsEqual extends true ? Index : _IndexOfArray> : -1; type _IndexOfString = T extends `${infer First}${infer Rest extends string}` ? IsEqual extends true ? Index : _IndexOfString> : -1; /** ------------------------------------------------------- * * ***Utility Type: `IndexOf`.*** * -------------------------------------------------------- * **Type version of `Array.prototype.indexOf()` and `String.prototype.indexOf()`.** * - Returns the index of the second argument in the first argument. * @example * ```ts * type Case1 = IndexOf<[1, 2, 3], 2>; // ➔ 1 * type Case2 = IndexOf<[1, 2, 3], 4>; // ➔ -1 * type Case3 = IndexOf<'123', '2'>; // ➔ 1 * type Case4 = IndexOf<'123', '4'>; // ➔ -1 * ``` */ type IndexOf = T extends string ? IsStringLiteral extends true ? _IndexOfString : never : T extends readonly unknown[] ? IsTuple extends true ? _IndexOfArray : never : never; /** ------------------------------------------------------- * * ***Utility Type: `IsArrayIndex`.*** * ------------------------------------------------------- * **Returns a boolean whether the passed argument is a valid array index.** * @example * ```ts * type Case1 = IsArrayIndex<1>; // ➔ true * type Case2 = IsArrayIndex<'1'>; // ➔ true * type Case3 = IsArrayIndex<-1>; // ➔ false * type Case4 = IsArrayIndex<"a">; // ➔ false * ``` */ type IsArrayIndex = T extends number ? And, IsGreaterOrEqual> : T extends string ? ParseNumber extends infer NumT extends number ? Not> extends true ? And, IsGreaterOrEqual> : false : false : never; /** ------------------------------------------------------- * * ***Utility Type: `IsArrayOrTuple`.*** * ------------------------------------------------------- * **Checks if a given type `T` is an array or tuple type.** * - This includes both mutable (`T[]`) and readonly (`readonly T[]`) arrays. * @template T - The type to check. * @example * type A = IsArrayOrTuple; * // ➔ true * type B = IsArrayOrTuple; * // ➔ true * type C = IsArrayOrTuple; // ➔ false */ type IsArrayOrTuple = T extends readonly any[] ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `IsConstructor`.*** * ------------------------------------------------------- * **Checks whether a given type `T` is a constructor type.** * * This utility evaluates to `true` if `T` has a constructor * signature, including constructors of **abstract classes**. * * It uses the `abstract new (...args) => instance` signature, * meaning it matches any type that represents a constructor — * even if the class cannot be instantiated directly. * * - **Behavior:** * - Evaluates to `true` if `T` has a compatible constructor signature. * - Optionally validates the **constructor parameter tuple** * and **instance type** using the generic parameters `A` and `R`. * * - **Difference from {@link IsNewable | `IsNewable`}:** * - `IsConstructor` returns `true` for **both concrete and abstract constructors**. * - `IsNewable` only returns `true` for constructors that can be * instantiated with `new`. * * In other words: * * ```ts * IsConstructor ⊇ IsNewable * ``` * * @template T - The type to check. * @template A - Expected constructor parameter tuple (default: `any[]`). * @template R - Expected instance type (default: `any`). * * @example * ```ts * class A {} * abstract class B {} * * type T1 = IsConstructor; * // ➔ true * type T2 = IsConstructor; * // ➔ true * ``` * * @example * ```ts * class User { * constructor(x: number, y: string) {} * } * * type T1 = IsConstructor; * // ➔ true * type T2 = IsConstructor; * // ➔ false * ``` * * @example * ```ts * type T1 = IsConstructor<() => void>; * // ➔ false * ``` */ type IsConstructor = T extends (abstract new (...args: A) => R) ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `IsFunction`.*** * ------------------------------------------------------- * **Checks if a given type `T` is a callable function type.** * @template T - The type to check. * @example * type A = IsFunction<() => void>; // ➔ true * type B = IsFunction; // ➔ false */ type IsFunction = T extends AnyFunction ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `Primitive`.*** * ------------------------------------------------------- * **Represents **all primitive types in JavaScript/TypeScript**, * including their literal variants.** * - **This type matches:** * - Core primitive types: * - `string`, `number`, `boolean`, `bigint`, `symbol`, `null`, `undefined`. * - Literal counterparts: * - `"foo"`, `42`, `true`, etc. * - ⚠️ ***Note:*** * - Unlike some definitions, this does **not** include `void` or `never`, * since they are TypeScript-specific keywords, not runtime primitives. * @example * ```ts * type A = Primitive; * // ➔ any strict primitive type * type B = "hello" extends Primitive ? true : false; * // ➔ true * type C = void extends Primitive ? true : false; * // ➔ false * ``` */ type Primitive = string | number | bigint | boolean | symbol | null | undefined; /** ------------------------------------------------------- * * ***Utility Type: `IsPrimitive`.*** * ------------------------------------------------------- * **Checks if a given type `T` is a **strict primitive type** in JavaScript/TypeScript, * including literal variants.** * - **Behavior:** * - ***Includes:*** * - `string`, `number`, `bigint`, `boolean`, `symbol`, `null`, `undefined`. * - Literal types like: `"foo"`, `42`, `true`. * - ***Excludes:*** * - `void` (absence of value). * - `never` (impossible type). * - `object`, `unknown`, `Date`, `arrays`, `functions`, etc. * @template T - The type to check * @example * ```ts * type A = IsPrimitive<"foo">; // ➔ true * type B = IsPrimitive; // ➔ true * type C = IsPrimitive; // ➔ true * type D = IsPrimitive; // ➔ true * type E = IsPrimitive<{}>; // ➔ false * type F = IsPrimitive; // ➔ false * type G = IsPrimitive; // ➔ false * type H = IsPrimitive; // ➔ false * type I = IsPrimitive; // ➔ false * type J = IsPrimitive; // ➔ false * type K = IsPrimitive<[]>; // ➔ false * type L = IsPrimitive<() => void>; // ➔ false * ``` */ type IsPrimitive = IsNever extends true ? false : T extends Primitive ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `IsRealPrimitive`.*** * ------------------------------------------------------- * **Checks if a given type `T` is a **real primitive type** in JavaScript/TypeScript, * based on runtime behavior, **excluding `null`** but including `undefined`.** * - **Behavior:** * - ***Includes:*** * - `string`, `number`, `bigint`, `boolean`, `symbol`, `undefined`. * - Literal types like: `"foo"`, `42`, `true`. * - ***Excludes:*** * - `null`. * - `never` (impossible type). * - Objects, arrays, functions, `Date`, `unknown`, etc. * - ⚠️ ***Note:*** * - This aligns with runtime `typeof` checks in JS: * - `typeof null === "object"`, * so `null` is excluded from **“real primitives”**. * @template T - The type to check. * @example * ```ts * type A = IsRealPrimitive<42>; // ➔ true * type B = IsRealPrimitive; // ➔ true * type C = IsRealPrimitive; // ➔ true * type D = IsRealPrimitive; // ➔ true * type E = IsRealPrimitive<{}>; // ➔ false * type F = IsRealPrimitive<[]>; // ➔ false * type G = IsRealPrimitive; // ➔ false * type H = IsRealPrimitive; // ➔ false * type I = IsRealPrimitive<() => void>; // ➔ false * ``` */ type IsRealPrimitive = T extends Exclude ? true : false; /** * Applies readonly behavior according to mode. * */ type ApplyReadonlyMode = Mode extends "remove" ? { -readonly [K in keyof T]: T[K] } : Mode extends "preserve" ? { readonly [K in keyof T]: T[K] } : { [K in keyof T]: T[K] }; /** --------------------------------------------------------------------------- * * ***Options for {@link Prettify|`Prettify`}.*** * --------------------------------------------------------------------------- * **Options for customizing the behavior of the {@link Prettify | **`Prettify`**} type utility.** */ type PrettifyOptions = { /** ------------------------------------------------------- * * ***recursive*** * ------------------------------------------------------- * **Enables **deep prettification** of types when set to `true`.** * @description * By default (`false`), {@link Prettify | **`Prettify`**} only flattens the **top-level shape** * of objects and intersections. Nested objects, arrays, and tuples remain as-is * unless this option is enabled. * - ***Behavior when `true`:*** * - **Plain objects**: Nested intersections are expanded recursively. * - **Arrays & tuples**: Each element type is recursively prettified. * - **Readonly handling**: Nested properties respect the `readonlyMode` option. * - **Functions, constructors, and built-in objects** (Set, Map, Date, Promise, etc.) * are **not** affected or expanded. * - **Nested intersections**: Combined properties are flattened recursively. * - ⚠️ ***Notes:*** * - Recursive mode only applies to **plain objects**, **arrays**, and **tuples**. * - Readonly modifiers on nested properties follow the `readonlyMode` rules: * - `"auto"` ➔ keep as-is * - `"remove"` ➔ strip readonly * - `"preserve"` ➔ make readonly * - Arrays and tuples maintain `readonly` if the original type is `readonly` and `readonlyMode` is `"auto"` or `"preserve"`. * @default false * @example * ```ts * type Nested = { * a: { * readonly b: { c: number } & { d: string } * } & { e: boolean }; * list: readonly ({ id: number } & { name: string })[]; * set: Set<{ x: number } & { y: string }>; * }; * * // Top-level only (default) * type Shallow = Prettify; * // ➔ { * // a: { readonly b: { c: number } & { d: string } } & { e: boolean }; * // list: readonly ({ id: number } & { name: string })[]; * // set: Set<{ x: number } & { y: string }>; * // } * * // Fully recursive flatten * type Deep = Prettify; * // ➔ { * // a: { readonly b: { c: number; d: string }; e: boolean }; * // list: readonly { id: number; name: string }[]; * // set: Set<{ x: number } & { y: string }>; // built-in ignored * // } * ``` */ recursive?: boolean; /** ------------------------------------------------------- * * ***readonlyMode*** * ------------------------------------------------------- * **Determines how `readonly` modifiers are applied to properties * when using {@link Prettify}.** * - **Modes:** * - `"auto"` ➔ Keep `readonly` exactly as in the original type (default). * - `"remove"` ➔ Remove all `readonly` modifiers. * - `"preserve"` ➔ Make all properties `readonly`. * - **Behavior:** * - Applies to both **top-level** and **nested properties** (if `recursive` is `true`). * - Arrays and tuples preserve or adjust `readonly` according to the selected mode: * - `"auto"` ➔ preserve array/tuple readonly as-is. * - `"remove"` ➔ array/tuple becomes mutable. * - `"preserve"` ➔ array/tuple becomes readonly. * - Functions, constructors, and built-in objects (Set, Map, Date, Promise, etc.) are **not affected**. * - Nested intersections respect `readonlyMode` recursively if `recursive` is enabled. * - ⚠️ ***Notes:*** * - For nested objects, `readonly` behavior only changes if `recursive: true`. * - `readonlyMode` does **not** override `readonly` on function parameters, methods, or constructors. * @default "auto" * @example * ```ts * type T = { readonly a: number; b: string }; * * // Default: auto * type Auto = Prettify; * // ➔ { readonly a: number; b: string } * * // Remove readonly * type Remove = Prettify; * // ➔ { a: number; b: string } * * // Force all readonly * type Preserve = Prettify; * // ➔ { readonly a: number; readonly b: string } * * // Recursive + preserve * type Nested = { * config: { readonly port: number } & { host: string } * }; * type RecursivePreserve = Prettify; * // ➔ { readonly config: { readonly port: number; readonly host: string } } * ``` */ readonlyMode?: Extract<"auto" | "remove" | "preserve", string>; /** --------------------------------- * * ***Skips applying the prettify transformation.*** * --------------------------------- * * When enabled, the output will be returned as-is without running the * prettify step. * * @default false * */ skipPrettify?: boolean; }; /** ------------------------------------------------------- * * ***DefaultPrettifyOptions*** * ------------------------------------------------------- * **Default options {@link Prettify | **`Prettify`**} used when no custom options are provided.** */ type DefaultPrettifyOptions = { skipPrettify: false; recursive: false; readonlyMode: "auto"; }; type MergeReadonlyIntersection = T extends readonly any[] ? T : T extends object ? { [K in keyof T]: T[K] } : T; /** ------------------------------------------------------- * * ***Utility Type: `Prettify`.*** * ------------------------------------------------------- * **Flattens and simplifies complex TypeScript types into a more * human-readable form, by forcing the compiler to expand intersections.** * @description * By default, only the **top-level shape** of an object is flattened. * To also prettify **nested objects**, set the `recursive` option. * - ⚠️ ***Note:*** * - `recursive: true` only affects **plain objects** and **arrays/tuples**. * - Built-in objects like `Set`, `Map`, `Date`, `Promise`, etc. * will **not** be recursively prettified. * - `readonly` handling is controlled via the `readonlyMode` option. * - **ℹ️ Options:** * - `recursive?: boolean` (default: `false`): * - Whether to recursively expand nested objects and intersections. * - `readonlyMode?: "auto" | "remove" | "preserve"` (default: `"auto"`): * - How `readonly` modifiers are treated: * - `"auto"` ➔ preserve `readonly` as-is (**default**). * - `"remove"` ➔ strip all `readonly`. * - `"preserve"` ➔ enforce `readonly` everywhere. * @template T - The type to prettify. * @template Options - Configuration options. * @example * ```ts * // --- Top-level only (default) --- * type T0 = Prettify<{ a: number } & { b: string }>; * // ➔ { a: number; b: string } * * // --- Recursive expansion of nested objects --- * type T1 = Prettify< * { a: { x: number } & { y: string } } & { b: boolean }, * { recursive: true } * >; * // ➔ { a: { x: number; y: string }; b: boolean } * * // --- Readonly handling modes --- * type T2 = { readonly id: number; name: string }; * * type R1 = Prettify; * // (default: readonlyMode = "auto") * // ➔ { readonly id: number; name: string } * * type R2 = Prettify; * // ➔ { id: number; name: string } * * type R3 = Prettify; * // ➔ { readonly id: number; readonly name: string } * * // --- Readonly + mutable intersection --- * type T3 = Prettify<{ readonly a: number } & { a: number; b: boolean }>; * // ➔ { a: number; b: boolean } * // (in "auto" mode, readonly lose over mutable) * * // --- Nested readonly with recursive --- * type T4 = Prettify< * { config: { readonly port: number } & { host: string } }, * { recursive: true } * >; * // ➔ { config: { readonly port: number; host: string } } * * // --- Arrays with readonly --- * type T5 = Prettify< * { list: readonly ({ id: number } & { name: string })[] }, * { recursive: true } * >; * // (readonly on array is preserved in "auto" mode) * // ➔ { list: readonly { id: number; name: string }[] } * * type T6 = Prettify< * { list: readonly ({ id: number } & { name: string })[] }, * { recursive: true; readonlyMode: "remove" } * >; * // ➔ { list: { id: number; name: string }[] } * * // --- Built-in objects are ignored (not expanded) --- * type T7 = Prettify< * { s: Set<{ a: number } & { b: string }> }, * { recursive: true } * >; * // ➔ { s: Set<{ a: number } & { b: string }> } * ``` */ type Prettify = Options["skipPrettify"] extends true ? T : IsPrimitive extends true ? T : IsFunction extends true ? T : IsConstructor extends true ? T : IsArrayOrTuple extends true ? ApplyReadonlyMode<{ [K in keyof T]: If, T[K]> }, Options["readonlyMode"]> : T extends NonPlainObject ? T : T extends object ? ApplyReadonlyMode, T[K]> }>, Options["readonlyMode"]> : T; /** --------------------------------------------------------------------------- * * ***Options for {@link Mutable | `Mutable`}.*** * --------------------------------------------------------------------------- * **Configuration options for the ***{@link Mutable | **`Mutable`**}*** type utilities.** * @example * ```ts * type Opt1 = MutableOptions; * // ➔ { recursive: boolean } * ``` */ type MutableOptions = { /** * ***Whether to make nested objects mutable recursively.*** * * - **Behavior:** * - If `true`, all nested objects will also have their `readonly` removed. * - Default value: `false`. * * @default false */ recursive: boolean; /** * ***Options forwarded to {@link Prettify | `Prettify`}.*** * * Controls how the resulting type is **normalized or formatted** * after the `readonly` modifiers are removed. * * - ***This can be useful to:*** * - Flatten intersections. * - Normalize mapped types. * - Improve editor type hints. * * @default DefaultPrettifyOptions */ prettifyOptions?: PrettifyOptions; }; /** ------------------------------------------------------- * * ***Utility Type: `Mutable`.*** * ------------------------------------------------------- * **Removes `readonly` from all properties of the passed type `T`.** * - If `Options["recursive"]` is `true`, nested objects are also made mutable. * @template T - The type to make mutable. * @template Options - Configuration options. Default: * `{ recursive: false, prettifyOptions: DefaultPrettifyOptions }`. * @example * ```ts * type Case1 = Mutable<{ readonly a: { readonly b: string } }>; * // ➔ { a: { b: string } } (non-recursive by default) * type Case2 = Mutable<{ readonly a: { readonly b: string } }, { recursive: true }>; * // ➔ { a: { b: string } } (nested properties also mutable) * ``` */ type Mutable = Prettify<{ -readonly [K in keyof T]: And> extends true ? Mutable : T[K] }>; /** ------------------------------------------------------- * * ***Utility Type: `MutableOnly`.*** * ------------------------------------------------------- * **Removes `readonly` only from the specified keys `K` of type `T`.** * @template T - The type to modify. * @template K - Keys to make mutable. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * type Case1 = MutableOnly<{ readonly a: string; readonly b: string }, "a">; * // ➔ { a: string; readonly b: string } * type Case2 = MutableOnly<{ readonly a: string; readonly b: string }, "a" | "b">; * // ➔ { a: string; b: string } * ``` */ type MutableOnly = Prettify> & { -readonly [P in K]: T[P] }, PrettifyOptions$12>; /** ------------------------------------------------------- * * ***Utility Type: `MutableExcept`.*** * ------------------------------------------------------- * **Removes `readonly` from all properties of `T` **except** the specified keys `K`.** * @template T - The type to modify. * @template K - Keys to keep as readonly. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * type Case1 = MutableExcept<{ readonly a: string; readonly b: string }, "b">; * // ➔ { a: string; readonly b: string } * type Case2 = MutableExcept<{ a: string; readonly b: string }, "a">; * // ➔ { a: string; b: string } (all except "a" made mutable) * ``` */ type MutableExcept = Prettify & { -readonly [P in Exclude]: T[P] }, PrettifyOptions$13>; /** ------------------------------------------------------- * * ***Utility Type: `IsArray`.*** * ------------------------------------------------------- * **Returns a boolean whether the passed argument is an array.** * @example * type Case1 = IsArray<[]>; * // ➔ true * type Case2 = IsArray; * // ➔ false */ type IsArray = AndArr<[Not>, Not>, Extends]>; /** ------------------------------------------------------- * * ***Utility Type: `IsMutableArray`.*** * ------------------------------------------------------- * **Returns a boolean whether the passed argument is a mutable array.** * @example * type Case1 = IsMutableArray<[]>; * // ➔ true * type Case2 = IsMutableArray; * // ➔ false */ type IsMutableArray = And, NotExtends, T>>; /** ------------------------------------------------------- * * ***Utility Type: `IsReadonlyArray`.*** * ------------------------------------------------------- * **Returns a boolean whether the passed argument is a read-only array.** * @example * type Case1 = IsReadonlyArray; * // ➔ true * type Case2 = IsReadonlyArray<[]>; * // ➔ false */ type IsReadonlyArray = And, NotExtends>>; /** ------------------------------------------------------- * * ***Utility Type: `Mod`.*** * ------------------------------------------------------- * **Returns the **remainder** of the division of two numbers (`Dividend % Divisor`).** * - **Behavior:** * - Computes the remainder using type-level arithmetic: * - `Dividend - (Divisor * (Dividend / Divisor))`. * - Works with integers within the range: * - `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Dividend - The dividend (numerator). * @template Divisor - The divisor (denominator). * @example * ```ts * type T0 = Mod<1, 2>; // ➔ 1 * type T1 = Mod<1, 3>; // ➔ 1 * type T2 = Mod<10, 3>; // ➔ 1 * type T3 = Mod<7, 7>; // ➔ 0 * ``` */ type Mod = Div extends infer Quotient extends number ? Multi extends infer Product extends number ? Sub : never : never; /** ------------------------------------------------------- * * ***Utility Type: `IsDivisibleByTwo`.*** * ------------------------------------------------------- * **Accepts an integer argument and returns a boolean whether it is divisible by two.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @example * // truthy * type Case1 = IsDivisibleByTwo<4>; // ➔ true * type Case2 = IsDivisibleByTwo<-6>; // ➔ true * * // falsy * type Case3 = IsDivisibleByTwo<3>; // ➔ false * type Case4 = IsDivisibleByTwo<-5>; // ➔ false */ type IsDivisibleByTwo = IsEven; type DivisibleByThreeMap = { 3: true; 6: true; 9: true; }; type _IsDivisibleByThree = DigitsTuple>["digits"] extends infer Digits extends readonly number[] ? IsEqual extends true ? Digits[0] extends keyof DivisibleByThreeMap ? true : false : SumArr extends infer DigitsSum extends number ? IfLowerThan extends true ? false : _IsDivisibleByThree : never : never; /** ------------------------------------------------------- * * ***Utility Type: `IsDivisibleByThree`.*** * ------------------------------------------------------- * **Accepts an integer argument and returns a boolean whether it is divisible by three.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @example * // truthy * type Case1 = IsDivisibleByThree<123>; // ➔ true * type Case2 = IsDivisibleByThree<-126>; // ➔ true * * // falsy * type Case3 = IsDivisibleByThree<124>; // ➔ false * type Case4 = IsDivisibleByThree<-128>; // ➔ false */ type IsDivisibleByThree = _IsDivisibleByThree; /** ------------------------------------------------------- * * ***Utility Type: `IsDivisibleByFive`.*** * ------------------------------------------------------- * **Accepts an integer argument and returns a boolean whether it is divisible by five.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @example * // truthy * type Case1 = IsDivisibleByFive<125>; // ➔ true * type Case2 = IsDivisibleByFive<-115>; // ➔ true * * // falsy * type Case3 = IsDivisibleByFive<13>; // ➔ false * type Case4 = IsDivisibleByFive<-17>; // ➔ false */ type IsDivisibleByFive = EndsWith, "0" | "5">; /** ------------------------------------------------------- * * ***Utility Type: `IsDivisibleBySix`.*** * ------------------------------------------------------- * **Accepts an integer argument and returns a boolean whether it is divisible by six.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @example * // truthy * type Case1 = IsDivisibleBySix<126>; // ➔ true * type Case2 = IsDivisibleBySix<-156>; // ➔ true * * // falsy * type Case3 = IsDivisibleBySix<124>; // ➔ false * type Case4 = IsDivisibleBySix<-139>; // ➔ false */ type IsDivisibleBySix = And, IsDivisibleByThree>; /** ------------------------------------------------------- * * ***Utility Type: `IsDivisibleByTen`.*** * ------------------------------------------------------- * **Accepts an integer argument and returns a boolean whether it is divisible by ten.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @example * // truthy * type Case1 = IsDivisibleByTen<100>; // ➔ true * type Case2 = IsDivisibleByTen<-80>; // ➔ true * * // falsy * type Case3 = IsDivisibleByTen<101>; // ➔ false * type Case4 = IsDivisibleByTen<-72>; // ➔ false */ type IsDivisibleByTen = EndsWith, "0">; /** ------------------------------------------------------- * * ***Utility Type: `IsDivisibleByHundred`.*** * ------------------------------------------------------- * **Accepts an integer argument and returns a boolean whether it is divisible by hundred.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @example * // truthy * type Case1 = IsDivisibleByHundred<100>; // ➔ true * type Case2 = IsDivisibleByHundred<-300>; // ➔ true * * // falsy * type Case3 = IsDivisibleByHundred<101>; // ➔ false * type Case4 = IsDivisibleByHundred<-210>; // ➔ false */ type IsDivisibleByHundred = EndsWith, "00">; /** ------------------------------------------------------- * * ***Utility Type: `IsDivisible`.*** * ------------------------------------------------------- * **Returns a boolean whether the first integer argument is divisible by the * second integer argument.** * @example * // truthy * type Case1 = IsDivisible<1024, 2>; // ➔ true * type Case2 = IsDivisible<2034, 3>; // ➔ true * * // falsy * type Case3 = IsDivisible<1023, 2>; // ➔ false * type Case4 = IsDivisible<3034, 3>; // ➔ false */ type IsDivisible = IsEqual, 0>; /** ------------------------------------------------------- * * ***Utility Type: `IsLetter`.*** * ------------------------------------------------------- * **Returns a boolean whether the passed argument is a letter (Only for letters that have both upper and lower case).** * @template T - The string to check. * @example * type Case1 = IsLetter<'a'>; // ➔ true * type Case2 = IsLetter<'1'>; // ➔ false */ type IsLetter = Uppercase extends Lowercase ? false : true; /** ------------------------------------------------------- * * ***Utility Type: `IsNewable`.*** * ------------------------------------------------------- * **Checks whether a given type `T` is a constructable (`new`) function type.** * * A *newable* type is any type that can be instantiated using the * `new` operator (for example, class constructors or constructor * signatures). * * This utility only matches **non-abstract constructors**, meaning * the type must be directly instantiable. * * - **Behavior:** * - Evaluates to `true` if `T` has a compatible * `new (...args) => instance` signature. * - Optionally validates the **constructor parameter tuple** * and **instance type** using the generic parameters `A` and `R`. * * - **Difference from {@link IsConstructor | `IsConstructor`}:** * - `IsNewable` only returns `true` for constructors that can be * instantiated with `new`. * - `IsConstructor` also returns `true` for **abstract constructors**. * * @template T - The type to check. * @template A - Expected constructor parameter tuple (default: `any[]`). * @template R - Expected instance type (default: `any`). * * @example * ```ts * class A {} * abstract class B {} * * type T1 = IsNewable; * // ➔ true * type T2 = IsNewable; * // ➔ false * ``` * * @example * ```ts * class User { * constructor(x: number, y: string) {} * } * * type T1 = IsNewable; * // ➔ true * type T2 = IsNewable; * // ➔ false * ``` * * @example * ```ts * type T1 = IsNewable<() => void>; * // ➔ false * type T2 = IsNewable; * // ➔ false * ``` */ type IsNewable = T extends (new (...args: A) => R) ? true : false; type _IsUnion = IsNever extends true ? false : T extends U ? Not>> : false; /** ------------------------------------------------------- * * ***Utility Type: `IsUnion`.*** * ------------------------------------------------------- * **Returns a boolean whether the passed argument is a union.** * @template T - The type to check. * @example * type Case1 = IsUnion<'a' | 'b'>; * // ➔ true * type Case2 = IsUnion<'a'>; * // ➔ false */ type IsUnion = _IsUnion; /** ------------------------------------------------------- * * ***Utility Type: `Join`.*** * ------------------------------------------------------- * **Type version of `Array.prototype.join()`.** * - Joins the first array argument by the second argument. * @template T - The array to join. * @template Glue - The string or number to join with, defaultValue: `""`. * @example * type Case0 = Join<["p", "e", "a", "r"]>; * // ➔ 'pear' * type Case1 = Join<["a", "p", "p", "l", "e"], "-">; * // ➔ 'a-p-p-l-e' * type Case2 = Join<["2", "2", "2"], 1>; * // ➔ '21212' * type Case3 = Join<["o"], "u">; * // ➔ 'o' * type Case3 = Join<[], "n">; * // ➔ never */ type Join = IsTuple extends true ? T extends readonly [infer First extends string | number, ...infer Rest extends readonly (string | number)[]] ? IfEmptyArray}`> : never : never; /** -------------------------------------------------- * * ***Utility Type: `AnyRecord`.*** * -------------------------------------------------- * **Represents an object with arbitrary string keys and values of **any** type.** * - ⚠️ **Use with caution — `any`** disables type safety. * - Prefer stricter like {@link UnknownRecord | **`UnknownRecord`**} typing when possible. * - ✅ Commonly used as a fallback for flexible key-value structures * such as query parameters, configuration maps, or JSON-like data. * @example * ```ts * const config: AnyRecord = { * mode: "dark", * retries: 3, * debug: true, * }; * ``` */ type AnyRecord = Record; /** -------------------------------------------------- * * ***Utility Type: `UnknownRecord`.*** * -------------------------------------------------- * **Represents an object with arbitrary string keys and values of **unknown** type.** * - ✅ Safer alternative to `AnyRecord` — forces explicit type narrowing * before values can be used, maintaining type safety. * - ✅ Suitable for working with untyped external data sources * (e.g., JSON APIs, parsed configs) where values must be validated first. * @example * ```ts * const data: UnknownRecord = JSON.parse("{}"); * * // Must narrow the type before usage * if (typeof data.id === "string") { * console.log(data.id.toUpperCase()); * } * * // Or: * const unknownObject: UnknownRecord = { * mode: "dark", * retries: 3, * debug: true, * }; * ``` */ type UnknownRecord = Record; /** ------------------------------------------------------- * * ***Utility Type: `AnyStringRecord`.*** * ------------------------------------------------------- * **Same as **{@link AnyString | **`AnyString`**}** but uses `Record` as the intersection.** * - This approach is often more reliable in preserving literal types * in generic inference scenarios. * @example * ```ts * declare function acceptsAnyStringRecord(value: T): T; * * const a = acceptsAnyStringRecord("hello"); * // ➔ "hello" * * const b = acceptsAnyStringRecord(String("world")); * // ➔ string * ``` */ type AnyStringRecord = Record & string; /** ------------------------------------------------------- * * ***Utility Type: `LooseLiteral`.*** * ------------------------------------------------------- * **Improves the autocompletion and inference of **loose literal types**.** * @description * Ensures that specified literal types are preserved while still * allowing assignment of a broader base type. * - **Useful in scenarios where:** * - You want to accept **specific literal values** but still allow * any value of a base type (like `string` or `number`). * - You want stricter typing in generics while preserving literals. * @template Literal - The literal type(s) to preserve. * @template BaseType - The base type to extend when not matching literal. * @example * ```ts * type T0 = LooseLiteral<"a" | "b" | "c", string>; * // ➔ "a" | "b" | "c" | (string & {}) * * declare function acceptsLoose>(value: T): T; * const a = acceptsLoose("x"); * // ➔ "x" * const b = acceptsLoose("any string"); * // ➔ string * ``` */ type LooseLiteral = Literal | (BaseType & AnyStringRecord); /** ------------------------------------------------------- * * ***Utility Type: `Max`.*** * ------------------------------------------------------- * **Accepts two integers and returns the **maximum** among them.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - First integer to compare. * @template Num2 - Second integer to compare. * @example * ```ts * type Case1 = Max<1, 10>; // ➔ 10 * type Case2 = Max<1, -10>; // ➔ 1 * ``` */ type Max = IfLowerThan; /** * ***Recursively computes the maximum number in a tuple of integers.*** * * @private ***Private internal type for {@link MaxArr | **`MaxArr`**}.*** * @template T - Tuple of numbers to process. * @template CurrentMax - Current maximum value, defaults to the first element of T. */ type _MaxArr> = IsEmptyArray extends true ? CurrentMax : Shift extends [infer Rest extends number[], infer First extends number] ? _MaxArr> : never; /** ------------------------------------------------------- * * ***Utility Type: `MaxArr`.*** * ------------------------------------------------------- * **Accepts a tuple of integers and returns the **maximum** among its elements.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template T - Tuple of numbers to evaluate. * - Only tuples are supported; arrays of unknown length will return `never`. * @example * ```ts * type Case1 = MaxArr<[1, 2, 4, 10]>; // ➔ 10 * type Case2 = MaxArr<[-1, 4, -10]>; // ➔ 4 * type Case3 = MaxArr; // ➔ never (not a tuple) * ``` */ type MaxArr = IsTuple extends true ? _MaxArr : never; /** ------------------------------------------------------- * * ***Utility Type: `DeepMergeArrayUnion`.*** * ------------------------------------------------------- * **Recursively merges element types of nested arrays inside an array type, * **preserving the nested array structure**.** * - Converts an array of nested arrays into a union of its element types, * while keeping the nested arrays intact. * @template T - The outer array type. * @returns The nested array type with merged element types. * @example * ```ts * const test = [ * ["a", null], * ["b", [undefined, "c"]], * ]; * * type Merged = DeepMergeArrayUnion; * // ➔ ((string | null | (string | undefined)[])[])[] * ``` */ type DeepMergeArrayUnion = T extends (infer U)[] ? U extends any[] ? DeepMergeArrayUnionHelper[] : U[] : never; type DeepMergeArrayUnionHelper = T extends (infer U)[] ? DeepMergeArrayUnionHelper | Exclude : T; /** ------------------------------------------------------- * * ***Utility Type: `Min`.*** * ------------------------------------------------------- * **Accepts two integers and returns the **minimum** among them.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template Num1 - First integer. * @template Num2 - Second integer. * @example * ```ts * type Case1 = Min<1, 10>; // ➔ 1 * type Case2 = Min<1, -10>; // ➔ -10 * ``` */ type Min = IfLowerThan; /** * ***Helper type for computing the minimum of a tuple of numbers recursively.*** * * @private ***Private internal type for {@link MinArr | **`MinArr`**}.*** * @template T - Array of numbers * @template CurrentMin - Current minimum in recursion */ type _MinArr> = IsEmptyArray extends true ? CurrentMin : Shift extends [infer Rest extends number[], infer First extends number] ? _MinArr> : never; /** ------------------------------------------------------- * * ***Utility Type: `MinArr`.*** * ------------------------------------------------------- * **Accepts an array of integers and returns the **minimum** among its elements.** * - Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`. * @template T - Tuple of numbers. * @example * ```ts * type Case1 = MinArr<[1, 2, 4, 10]>; // ➔ 1 * type Case2 = MinArr<[-1, 4, -10]>; // ➔ -10 * ``` */ type MinArr = IsTuple extends true ? _MinArr : never; /** -------------------------------------------------- * * ***Utility Type: `Nullish`.*** * -------------------------------------------------- * **Useful as a shorthand when working with optional or missing values.** * - **Represents all values considered **`nullish`**:** * - `null` * - `undefined` */ type Nullish = null | undefined; /** -------------------------------------------------- * * ***Utility Type: `Nullable`.*** * -------------------------------------------------- * **Represents a type that can be either `T` or `null`.** * @template T - The base type. * @example * ```ts * type A = Nullable; // ➔ string | null * ``` */ type Nullable = T | null; /** -------------------------------------------------- * * ***Utility Type: `Nilable`.*** * -------------------------------------------------- * **Represents a type that can be either `T`, `null`, or `undefined`.** * @template T - The base type. * @example * ```ts * type A = Nilable; // ➔ number | null | undefined * ``` */ type Nilable = T | null | undefined; /** -------------------------------------------------- * * ***Utility Type: `Undefinedable`.*** * -------------------------------------------------- * **Represents a type that can be either `T` or `undefined`.** * @template T - The base type. * @example * ```ts * type A = Undefinedable; // ➔ boolean | undefined * ``` */ type Undefinedable = T | undefined; /** ------------------------------------------------------- * * ***Utility Type: `NonNil`.*** * ------------------------------------------------------- * **Removes both `null` and `undefined` from the given type `T`.** * @template T - The type to filter. * @example * ```ts * type A = NonNil; * // ➔ string * type B = NonNil; * // ➔ number * type C = NonNil; * // ➔ never * type D = NonNil; * // ➔ boolean * ``` */ type NonNil = T extends null | undefined ? never : T; /** ------------------------------------------------------- * * ***Utility Type: `NonNull`.*** * ------------------------------------------------------- * **Removes `null` from the given type `T`.** * @template T - The type to filter. * @example * ```ts * type A = NonNull; * // ➔ string * type B = NonNull; * // ➔ number | undefined * type C = NonNull; * // ➔ never * ``` */ type NonNull = T extends null ? never : T; /** ------------------------------------------------------- * * ***Utility Type: `NonUndefined`.*** * ------------------------------------------------------- * **Remove `undefined` from the given type `T`.** * @template T - The type to filter. * @example * ```ts * type A = NonUndefined; * // ➔ string * type B = NonUndefined; * // ➔ number | null * type C = NonUndefined; * // ➔ never * ``` */ type NonUndefined = T extends undefined ? never : T; /** -------------------------------------------------- * * ***Utility Type: `KeepNil`.*** * -------------------------------------------------- * **Keeps `null` and/or `undefined` in the output type **only if** they * exist in the input type `T`, otherwise, resolves to `never`.** * @template T - Input type to check for `null` and `undefined`. * @example * ```ts * type A = KeepNil; * // ➔ null * type B = KeepNil; * // ➔ undefined * type C = KeepNil; * // ➔ null | undefined * type D = KeepNil; * // ➔ never * ``` */ type KeepNil = (null extends T ? null : never) | (undefined extends T ? undefined : never); /** -------------------------------------------------- * * ***Utility Type: `KeepNull`.*** * -------------------------------------------------- * **Keeps `null` in the output type **only if** the input type `T` includes `null`, otherwise resolves to `never`.** * @template T - Input type to check for `null`. * @example * ```ts * type A = KeepNull; // ➔ null * type B = KeepNull; // ➔ never * ``` */ type KeepNull = null extends T ? null : never; /** -------------------------------------------------- * * ***Utility Type: `KeepUndef`.*** * -------------------------------------------------- * **Keeps `undefined` in the output type **only if** the input type `T` includes `undefined`, otherwise resolves to `never`.** * @template T - Input type to check for `undefined`. * @example * ```ts * type A = KeepUndef; // ➔ undefined * type B = KeepUndef; // ➔ never * ``` */ type KeepUndef = undefined extends T ? undefined : never; /** ------------------------------------------------------- * * ***Utility Type: `NullToUndefined`.*** * ------------------------------------------------------- * **Transforms `null` or `undefined` types into `undefined`, otherwise, returns * the original type `T` unchanged.** * @template T - The input type to transform. * @example * ```ts * type A = NullToUndefined; // ➔ undefined * type B = NullToUndefined; // ➔ undefined * type C = NullToUndefined; // ➔ string * type D = NullToUndefined; // ➔ null[] * type E = NullToUndefined<(string | null)[]>; // ➔ (string | null)[] * ``` */ type NullToUndefined = T extends null ? undefined : T extends undefined ? undefined : T; /** ------------------------------------------------------- * * ***Utility Type: `NonNullableObject`.*** * ------------------------------------------------------- * **Makes all properties of the object type `T` non-nullable.** * @template T - Object type to transform. * @example * ```ts * type A = NonNullableObject<{ a: string | null; b: number | undefined }>; * // ➔ { a: string; b: number } * ``` */ type NonNullableObject = { [K in keyof T]: NonNullable }; /** ------------------------------------------------------- * * ***Utility Type: `NonNullableObjectOnly`.*** * ------------------------------------------------------- * **Makes only the specified properties `K` of the object type `T` non-nullable.** * @template T - Object type to transform. * @template K - Keys of `T` to make non-nullable. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * type A = NonNullableObjectOnly< * { a: string | null; b: number | undefined; c: boolean | null }, * "a" | "b" * >; * // ➔ { a: string; b: number; c: boolean | null } * ``` */ type NonNullableObjectOnly = Prettify> & { [P in K]: NonNullable }, PrettifyOptions$10>; /** ------------------------------------------------------- * * ***Utility Type: `NonNullableObjectExcept`.*** * ------------------------------------------------------- * **Makes all properties of the object type `T` non-nullable except for the specified properties `K`.** * @template T - Object type to transform. * @template K - Keys of `T` to leave unchanged. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * type A = NonNullableObjectExcept< * { a: string | null; b: number | undefined; c: boolean | null }, * "c" * >; * // ➔ { a: string; b: number; c: boolean | null } * ``` */ type NonNullableObjectExcept = Prettify & { [P in Exclude]: NonNullable }, PrettifyOptions$11>; /** -------------------------------------------------- * * ***Internal Utility Type for: {@link NumberRangeUnion | `NumberRangeUnion`}.*** * -------------------------------------------------- * @template N - Starting/Ending number of the range (inclusive). * @template Acc - Internal accumulator for recursion (do not set manually). */ type Enumerate = Acc["length"] extends N ? Acc[number] : Enumerate; /** -------------------------------------------------- * * ***Utility Type: `NumberRangeUnion`.*** * -------------------------------------------------- * **Generate a union type of numbers from `From` to `To` using enumeration.** * @description * Produces a **numeric union type** from `From` to `To` (inclusive), * using a simpler approach based on `Enumerate` helper type. * - ✅ Straightforward & easy to reason about. * - ⚠️ Still limited by TypeScript recursion depth (safe up to `999`). * - ⚙️ Best used for **smaller ranges** (`≤ 100`) or when readability matters. * - ℹ️ For **larger ranges** (`≥ 101`) use {@link NumberRangeLimit | `NumberRangeLimit`} instead. * @template From - Starting number of the range (inclusive). * @template To - Ending number of the range (inclusive). * @example * ```ts * type RangeA = NumberRangeUnion<3, 6>; * // ➔ 3 | 4 | 5 | 6 * type RangeB = NumberRangeUnion<0, 2>; * // ➔ 0 | 1 | 2 * type RangeC = NumberRangeUnion<8, 8>; * // ➔ 8 * type RangeD = NumberRangeUnion<20, 10>; * // ➔ 10 * ``` */ type NumberRangeUnion = From extends To ? From : Exclude, Enumerate> extends never ? To : Exclude, Enumerate> | To; /** -------------------------------------------------- * * ***Internal Utility Type for: {@link NumberRangeLimit | `NumberRangeLimit`}.*** * -------------------------------------------------- * @template From - Starting number of the range (inclusive). * @template To - Ending number of the range (inclusive). * @template Result - Internal accumulator for recursion (do not set manually). */ type _NumberRangeLimit = IsGreaterThan extends true ? [...Result, To][number] extends infer R extends number ? R extends R ? IsGreaterThan extends true ? never : R : never : never : _NumberRangeLimit, To, [...Result, From, Sum, Sum, Sum, Sum, Sum, Sum]>; /** -------------------------------------------------- * * ***Utility Type: `NumberRangeLimit`.*** * -------------------------------------------------- * **Generate a union type of numbers within a specified range (optimized recursive batching).** * @description * Produces a **numeric union type** from `From` to `To` (inclusive), * using ***batched recursive expansion*** (**adds up to `7` numbers at a time**). * * This batching allows generating **larger ranges** (`≥ 101`) efficiently without * hitting TypeScript’s recursion limits too quickly. * - ✅ Optimized for **performance** (fewer recursive steps). * - ⚠️ Supports up to `To = 999` safely. * - ⚙️ Best used for **larger ranges** (`≥ 101`) or when you need **arbitrary ranges** within `0–999`. * - ℹ️ For **smaller ranges** (`≤ 100`) or when readability matters use {@link NumberRangeUnion | **`NumberRangeUnion`**} instead. * @template From - Starting number of the range (inclusive). * @template To - Ending number of the range (inclusive). * @example * ```ts * type RangeA = NumberRangeLimit<5, 8>; * // ➔ 5 | 6 | 7 | 8 * type RangeB = NumberRangeLimit<10, 15>; * // ➔ 10 | 11 | 12 | 13 | 14 | 15 * type RangeC = NumberRangeLimit<8, 8>; * // ➔ 8 * type RangeD = NumberRangeLimit<20, 10>; * // ➔ 10 * ``` */ type NumberRangeLimit = _NumberRangeLimit; /** -------------------------------------------------- * * ***Utility Type: `OmitStrict`.*** * -------------------------------------------------- * **Strictly omits keys `K` from type `T`, with optional flattening for readability using `Prettify`.** * - **Behavior:** * - ✅ Enhances autocomplete and type inspection clarity in editors. * - ✅ Optionally flattens nested intersections or mapped types into a cleaner shape. * @template T - The original object type. * @template K - The keys to omit from `T`. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * type A = { a: number; b: string; c: boolean }; * type B = OmitStrict; * // ➔ { a: number; c: boolean } * * type C = OmitStrict; * // ➔ Omit without prettifying, keeps intersection structure * * type D = OmitStrict; * // ➔ Prettifies only top level, does not recurse into nested objects * ``` */ type OmitStrict = Prettify, PrettifyOptions$9>; /** ---------------------------------------------------------------- * * ***Options for {@link OverrideTypes | `OverrideTypes`}.*** * ---------------------------------------------------------------- * Configuration options controlling how overriding behaves. */ type OverrideTypesOptions = { /** * ***Whether overriding keys must exist in the base type `T`.*** * * - If `true`, all keys of `U` must exist in `T`. * - If `false`, additional keys from `U` are allowed and will be added * to the resulting type. * * @default true */ strictKeys: boolean; /** * ***Options forwarded to {@link Prettify | `Prettify`}.*** * * Controls how the resulting type is normalized. */ prettifyOptions?: PrettifyOptions; }; type StrictOverrideConstraint = Strict extends true ? { [K in keyof U]: K extends keyof T ? unknown : never } : unknown; type ResolvePrettifyOptions = O["prettifyOptions"] extends PrettifyOptions ? O["prettifyOptions"] : DefaultPrettifyOptions; /** -------------------------------------------------- * * ***Utility Type: `OverrideTypes`.*** * -------------------------------------------------- * Overrides properties in type `T` using properties from type `U`. * * Keys that exist in both `T` and `U` will take the value type from `U`, * while all other properties from `T` remain unchanged. * * The behavior can be configured using {@link OverrideTypesOptions}. * * @template T - The base object type whose properties will be overridden. * @template U - The object type providing overriding property types. * @template Options - Configuration controlling override behavior. * * @remarks * - When `Options["strictKeys"]` is `true` (default), all keys in `U` * **must already exist in `T`**. * - When `strictKeys` is `false`, `U` may introduce **additional keys** * which will be added to the resulting type. * - The resulting type is normalized using {@link Prettify}. * * @example * // Basic override * type A = { a: number; b: string }; * type B = { b: boolean }; * type C = OverrideTypes; * // Result: * // { * // a: number; * // b: boolean; * // } * * @example * // Strict key enforcement (default) * type A = { a: number; b: string }; * type B = { x: string[]; b: boolean }; * // @ts-expect-error * type C = OverrideTypes; * // Error: "x" is not assignable to keyof A * * @example * // Allow additional keys * type A = { a: number; b: string }; * type B = { x: string[]; b: boolean }; * type C = OverrideTypes; * // Result: * // { * // a: number; * // b: boolean; * // x: string[]; * // } * * @example * // Custom Prettify options * type A = { a: number; b: string }; * type B = { b: boolean }; * type C = OverrideTypes< * A, * B, * { * strictKeys: true; * prettifyOptions: { skipPrettify: true }; * } * >; */ type OverrideTypes, Options extends OverrideTypesOptions = { strictKeys: true; prettifyOptions: DefaultPrettifyOptions; }> = Options["strictKeys"] extends true ? Exclude extends never ? Prettify, ResolvePrettifyOptions> & U, ResolvePrettifyOptions> : never : Prettify, ResolvePrettifyOptions> & { [K in keyof U]: U[K] }, ResolvePrettifyOptions>; type _IsPalindrome = IsEmptyString extends true ? true : Not> extends true ? false : T extends `${infer First extends string}${infer Rest extends string}` ? IsEmptyString extends true ? true : Rest extends `${infer NewRest extends string}${First}` ? _IsPalindrome : false : false; /** ------------------------------------------------------- * * ***Utility Type: `IsPalindrome`.*** * ------------------------------------------------------- * **Determines if a string or number is a **palindrome** at type-level. * A palindrome reads the same forwards and backwards (e.g., `"racecar"`).** * @template T - A string or number to check. * @example * ```ts * type T0 = IsPalindrome<"racecar">; // true * type T1 = IsPalindrome<"hello">; // false * type T2 = IsPalindrome<12321>; // true * type T3 = IsPalindrome<12345>; // false * ``` * @remarks * - Converts numbers to strings using {@link Stringify | **`Stringify`**}. * - Uses {@link IsEmptyString | **`IsEmptyString`**}, * {@link IsStringLiteral | **`IsStringLiteral`**}, * and {@link Not | **`Not`**} for type-level logic. * - Returns `true` if the input is a palindrome, otherwise `false`. */ type IsPalindrome = _IsPalindrome>; /** ------------------------------------------------------- * * ***Utility Type: `UnionToIntersection`.*** * ------------------------------------------------------- * **Converts a union type into an **intersection**.** * @description * 📖 Reference: ***[`StackOverflow`](https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type/50375286#50375286).*** * @template U - The union type to be converted. * @example * ```ts * type A = UnionToIntersection<{ a: string } | { b: number }>; * // ➔ { a: string } & { b: number } * type B = UnionToIntersection< * { a: string } | { b: number } | { c: boolean } * >; * // ➔ { a: string } & { b: number } & { c: boolean } * ``` */ type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; /** ------------------------------------------------------- * * ***Utility Type: `PrettifyUnionIntersection`.*** * ------------------------------------------------------- * **Converts a union type into an **intersection** using ***{@link UnionToIntersection | `UnionToIntersection`}***, and then * applies ***{@link Prettify | `Prettify`}*** to simplify the resulting intersection * for better readability in IntelliSense and tooltips.** * @description * Useful when the raw intersection of union types produces * deeply nested or hard-to-read structures. * @template T - The union type to be converted. * @template Options - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * // Basic union ➔ intersection * type A = { a: string } | { b: number }; * type B = PrettifyUnionIntersection; * // ➔ { a: string } & { b: number } * // final result become ➔ { a: string b: number } * * // Larger union * type C = { a: string } | { b: number } | { c: boolean }; * type D = PrettifyUnionIntersection; * // ➔ { a: string } & { b: number } & { c: boolean } * // final result become ➔ { a: string b: number c: boolean } * * // With PrettifyOptions (custom formatting) * type E = PrettifyUnionIntersection; * ``` */ type PrettifyUnionIntersection = Prettify, Options>; /** Internal Helper */ /** Get optional keys of an object */ type OptionalKeys = { [P in keyof T]-?: {} extends Pick ? P : never }[keyof T]; /** Get required keys of an object */ type RequiredKeys = Exclude>; /** Remove duplicate `undefined` from unions */ type CleanOptional$1 = [T] extends [undefined] ? undefined : undefined extends T ? Exclude | undefined : T; /** Required keys only (no optional ones) */ type RequiredKeysOf = Exclude>; /** Force re-evaluation / cleaner display */ /** ------------------------------------------------------- * * ***Utility Type: `PartialOnly`.*** * ------------------------------------------------------- * **Make only the specified properties in `T` **optional**, while keeping all * other properties required.** * @template T - The object type to transform. * @template K - Keys of `T` that should become optional. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * // Only "a" is optional, "b" and "c" remain required * type T0 = PartialOnly<{ a: string; b: number; c: boolean }, "a">; * // ➔ { a?: string; b: number; c: boolean } * * // Both "a" and "b" are optional * type T1 = PartialOnly<{ a: string; b: number; c: boolean }, "a" | "b">; * // ➔ { a?: string; b?: number; c: boolean } * * // Only "a" is optional (since "x" is not a valid key of T) * type T2 = PartialOnly<{ a: string; b: number; c: boolean }, "a" | "x">; * // ➔ { a?: string; b: number; c: boolean } * ``` * - ℹ️ ***If key is never or not in object, all properties remain required:*** * * ```ts * type Skip1 = PartialOnly<{ a: string; b: number; c: boolean }, "x">; * // ➔ { a: string; b: number; c: boolean } * * type Skip2 = PartialOnly<{ a: string; b: number; c: boolean }, never>; * // ➔ { a: string; b: number; c: boolean } * ``` */ type PartialOnly = IsNever extends true ? T : PrettifyUnionIntersection<{ [P in Exclude, Extract>]-?: T[P] } & { [P in Exclude, Extract>]+?: CleanOptional$1 } & { [P in Extract]+?: CleanOptional$1 }, PrettifyOptions$7>; /** ------------------------------------------------------- * * ***Utility Type: `PartialExcept`.*** * ------------------------------------------------------- * **Make all properties in `T` **optional**, except for the ones specified * in `K`, which remain as-is.** * - **Behavior:** * - If a property in `K` is originally required ➔ it stays required. * - If a property in `K` is originally optional ➔ it stays optional. * - All other properties become optional. * - Duplicate `undefined` types are cleaned up automatically. * @template T - The object type to transform. * @template K - Keys of `T` that should remain as-is (not forced optional). * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * // "a" remains required, "b" and "c" become optional * type T0 = PartialExcept<{ a: string; b: number; c: boolean }, "a">; * // ➔ { a: string; b?: number; c?: boolean } * * // "a" and "b" remain required, "c" becomes optional * type T1 = PartialExcept<{ a: string; b: number; c: boolean }, "a" | "b">; * // ➔ { a: string; b: number; c?: boolean } * * // "b" is originally optional, so it stays optional, * // "a" stays required, "c" becomes optional * type T2 = PartialExcept<{ a: string; b?: number; c: boolean }, "a" | "b">; * // ➔ { a: string; b?: number; c?: boolean } * * // none of the keys match ➔ everything optional * type T3 = PartialExcept<{ a: string; b: number; c: boolean }, "x">; * // ➔ { a?: string; b?: number; c?: boolean } * ``` * - ℹ️ ***If key is never, all properties become optional:*** * ```ts * type Skip = PartialExcept<{ a: string; b: number; c: boolean }, never>; * // ➔ { a?: string; b?: number; c?: boolean } * ``` */ type PartialExcept = IsNever extends true ? Partial : PrettifyUnionIntersection> & { [P in Exclude]?: T[P] }>>]-?: CleanOptional$1> & { [P in Exclude]?: T[P] }>[P]> } & { [P in OptionalKeys> & { [P in Exclude]?: T[P] }>>]+?: CleanOptional$1> & { [P in Exclude]?: T[P] }>[P]> }>, PrettifyOptions$8>; /** ------------------------------------------------------- * * ***Utility Type: `ValueOf`.*** * ------------------------------------------------------- * **Gets the types of all property values in an object `T`.** * @template T - The object type. * @example * ```ts * type Case1 = ValueOf<{ a: string, b: number }>; * // ➔ string | number * ``` */ type ValueOf = T[keyof T]; /** ------------------------------------------------------- * * ***Utility Type: `ValueOfOnly`.*** * ------------------------------------------------------- * **Gets the types of properties in object `T` specified by `K`.** * @template T - The object type. * @template K - Keys of `T` to extract values from. * @example * ```ts * type Case1 = ValueOfOnly<{ a: string, b: number }, "a">; * // ➔ string * ``` */ type ValueOfOnly = T[K]; /** ------------------------------------------------------- * * ***Utility Type: `ValueOfExcept`.*** * ------------------------------------------------------- * **Gets the types of properties in object `T` **except** for keys in `K`.** * @template T - The object type. * @template K - Keys of `T` to exclude. * @example * ```ts * type Case1 = ValueOfExcept<{ a: string, b: number }, "a">; * // ➔ number * ``` */ type ValueOfExcept = T[keyof Omit]; /** ------------------------------------------------------- * * ***Utility Type: `ValueOfArray`.*** * ------------------------------------------------------- * **Gets the types of elements in a tuple or array `T`.** * @template T - The tuple or array type. * @example * ```ts * type Case1 = ValueOfArray<[string, number]>; * // ➔ string | number * ``` */ type ValueOfArray = T[number]; /** ------------------------------------------------------- * * ***Utility Type: `OverWritable`.*** * ------------------------------------------------------- * **Option type to signal that some properties can be overwritten when * applying default options.** * @property overwriteDefault - If true, all options in the passed `Options` * object will **overwrite** defaults, even if rules say otherwise. */ type OverWritable = { /** If true, all options in the passed `Options` object will **overwrite** defaults, even if rules say otherwise, defaultValue: `false`. * * @default false */ overwriteDefault?: boolean; }; /** ------------------------------------------------------- * * ***Utility Type: `ApplyDefaultOptions`.*** * ------------------------------------------------------- * **Type-level utility that merges a user-specified `Options` object * with a `DefaultOptions` object using a set of `OverwriteRules`.** * @template BaseOptions - The base type of all options. * @template Options - User-specified options that may override defaults. * @template DefaultOptions - Default values for options. * @template OverwriteRules - A mapping that indicates which keys * should always allow overwriting defaults. * @template OverwriteDefault - If true, all options in `Options` * overwrite defaults regardless of rules. * @remarks * - Recursively applies defaults for nested objects. * - Only objects that are non-nullable and non-unknown are recursively merged. * - If a property is **not an object** or recursion is not needed, * it either takes the value from `Options` or merges `Options[K] | DefaultOptions[K]`. * - Helps safely build strongly typed configuration objects with defaults. * @example * ```ts * type Base = { * a: { x: number; y: string }; * b: boolean; * }; * * type Defaults = { * a: { x: 1; y: "default" }; * b: true; * }; * * type UserOptions = { * a: { y: "custom" }; * }; * * type Result = ApplyDefaultOptions; * // Result: { * // a: { x: 1; y: "custom"; tra: "test" }; * // b: boolean; * // } * ``` */ type ApplyDefaultOptions = Prettify<{ [K in keyof BaseOptions]-?: K extends keyof Options ? AndArr<[Extends, object>, Not>, Not>]> extends true ? ApplyDefaultOptions, Extract>, Extract>, OverwriteRules[K & keyof OverwriteRules], OverwriteDefault> & { tra: "test"; } : Or, And, Extends>> extends true ? Options[K] : Options[K] | DefaultOptions[K] : DefaultOptions[K] }>; /** -------------------------------------------------------------- * * ***Options for {@link PathToFields | **`PathToFields`**} type-level utility.*** * -------------------------------------------------------------- * @template ignoredTypes - Types to ignore completely. * @template stopTypes - Types at which recursion stops and returns `[]`. * @template limit - Max recursion depth. * @template format - Output format, `"dot"` or `"array"`. * @template ignoredKeys - Keys to ignore when generating paths. * @template arrayIndexing - Options for handling array paths. */ type PathToFieldsOptions = Prettify; /** * ***Default options for {@link PathToFields}.*** * */ type DefaultPathToFieldsOptions = { ignoredTypes: never; stopTypes: string | number | boolean | symbol | Date | AnyFunction; format: "dot"; limit: 10; ignoredKeys: never; arrayIndexing: { exactIndexes: false; }; }; type OverwriteRules = { limit: true; format: true; arrayIndexing: { exactIndexes: true; }; }; type Booleanize = T extends true ? true : false; type _PathToFieldsArray = And, IsEqual, true>> extends true ? ValueOfArray<{ [K in keyof T]: IsArrayIndex extends true ? [K, ..._PathToFields>] : never }> : ArrayElementType extends infer ElementType ? [`${number}`, ...(ElementType extends ElementType ? _PathToFields> : never)] : never; type _PathToFields = T extends Options["ignoredTypes"] ? never : T extends Options["stopTypes"] ? [] : IsEqual extends true ? never : T extends readonly unknown[] ? _PathToFieldsArray : ValueOf<{ [K in Exclude]: NonNullable extends infer NonNullableFields ? NonNullableFields extends readonly unknown[] ? [K, ..._PathToFieldsArray] : [K, ..._PathToFields>] : never }>; /** ------------------------------------------------------- * * ***Utility Type: `PathToFields`.*** * ------------------------------------------------------- * **Generates **all possible property paths** within a type `T`. * Supports nested objects, arrays, tuples, and optional configuration.** * @template T - Object type to extract paths from. * @template Options - Optional configuration. * @example * ```ts * // Nested object * type T1 = PathToFields<{ a: { b: { c: number } } }>; * // Result: "a.b.c" * * // Array of objects (dot notation, default) * type T2 = PathToFields<{ arr: { id: string; value: number }[] }>; * // Result: "arr.${number}.id" | "arr.${number}.value" * * // Output format as array of path segments * type T4 = PathToFields< * { user: { profile: { name: string } } }, * { format: "array" } * >; * // Result: ["user", "profile", "name"] * * // Ignoring specific keys * type T5 = PathToFields< * { id: string; password: string; profile: { bio: string } }, * { ignoredKeys: "password" } * >; * // Result: "id" | "profile.bio" * * // Stopping recursion at specific types * type T6 = PathToFields< * { settings: Date; nested: { inner: number } }, * { stopTypes: Date } * >; * // Result: "settings" | "nested.inner" * ``` * @remarks * - `Options.format = "dot"` ➔ dot-notation strings, default output (`"a.b.c"`). * - `Options.format = "array"` ➔ array of path segments (`["a", "b", "c"]`). * - `Options.limit` ➔ max recursion depth (default 10). * - `Options.stopTypes` ➔ types at which recursion stops. * - `Options.ignoredTypes` ➔ types ignored completely. * - `Options.ignoredKeys` ➔ keys to skip when generating paths. * - `Options.arrayIndexing.exactIndexes = true` ➔ outputs exact tuple indexes (`"arr.0"`), otherwise generic `"arr.${number}"`. */ type PathToFields = (IsNever extends true ? DefaultPathToFieldsOptions : ApplyDefaultOptions, Options, DefaultPathToFieldsOptions, OverwriteRules, PathToFieldsOptions["overwriteDefault"] extends boolean ? PathToFieldsOptions["overwriteDefault"] : false>) extends infer MergedOptions extends PathToFieldsOptions ? _PathToFields extends infer Paths extends readonly (string | number)[] ? IsEqual extends true ? Paths extends Paths ? Join : never : Paths : never : never; /** -------------------------------------------------- * * ***Utility Type: `PickStrict`.*** * -------------------------------------------------- * **Utility type that behaves exactly like the native `Pick`, * but can help with type inference and IDE autocomplete in stricter scenarios.** * @template T - The base object type. * @template K - The keys from `T` to be picked. * @example * ```ts * type A = { a: number; b: string; c: boolean }; * type B = PickStrict; * // ➔ { a: number; c: boolean } * ``` */ type PickStrict = Pick; type _Pow = IsEqual extends true ? CurrentProduct : _Pow, Push>; /** ------------------------------------------------------- * * ***Utility Type: `Pow`.*** * ------------------------------------------------------- * **Returns a type-level **exponentiation** result:** * - Raises the first integer parameter (`Num`) to the power of the second * integer parameter (`Factor`). * @template Num - The base number (integer). * @template Factor - The exponent number (integer, >= 0). * @example * ```ts * type Case1 = Pow<10, 2> * // ➔ 100 * type Case2 = Pow<5, 0> * // ➔ 1 * type Case3 = Pow<2, 3> * // ➔ 8 * ``` */ type Pow = _Pow; /** -------------------------------------------------- * * ***Utility Type: `Awaitable`.*** * -------------------------------------------------- * **Represents a type that can be awaited:** * - Either a plain value `T` or a `PromiseLike`. * @template T - The inner value type. * @example * ```ts * async function wrap(v: Awaitable): Promise { * return await v; * } * * const a = wrap(42); // Promise * const b = wrap(Promise.resolve("hi")); // Promise * ``` */ type Awaitable = T | PromiseLike; /** -------------------------------------------------- * * ***Utility Type: `StrictAwaitable`.*** * -------------------------------------------------- * **Represents a value that may be synchronous or a * native `Promise`.** * * Unlike {@link Awaitable | `Awaitable`}, this type **does not accept * arbitrary thenables (`PromiseLike`)** and only allows * real `Promise` instances. * * This is sometimes preferred for **tooling APIs or * controlled async flows** where supporting generic * thenables is unnecessary or undesirable. * * -------------------------------------------------- * @template T - The inner value type. * * @example * ```ts * function maybeAsync(v: StrictAwaitable): Promise { * return Promise.resolve(v); * } * * maybeAsync(123); // Promise * maybeAsync(Promise.resolve("ok")); // Promise * ``` */ type StrictAwaitable = T | Promise; interface CustomPromiseLike { /** * Attaches callbacks for the resolution and/or rejection of the Promise. * @param onfulfilled The callback to execute when the Promise is resolved. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ then(onfulfilled?: ((value: OnSuccess) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: OnError) => TResult2 | PromiseLike) | null | undefined): CustomPromiseType; /** * Attaches a callback for only the rejection of the Promise. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of the callback. */ catch(onrejected?: ((reason: OnError) => TResult | PromiseLike) | null | undefined): CustomPromiseType; /** * Registers a callback to be invoked **exactly once** when the * promise settles, with access to both the resolved value and * the rejection reason. * * If the promise is already settled when `finish` is called, * the callback executes immediately on the same tick. * * @param cb Callback receiving the final `(value, error)`. * @returns `this` for fluent chaining. */ finish(cb: (value: OnSuccess | undefined, error: OnError | undefined) => void): CustomPromiseType; } /** -------------------------------------------------- * * ***Utility Type: `CustomPromiseType`.*** * -------------------------------------------------- * **Extends the native `Promise` type to provide explicit typing * for both the resolved (`onSuccess`) and rejected (`onError`) values, * plus an optional `finish` hook.** * - **Behavior:** * - ✅ **Strongly types** `success`, `error`, and `finish` handlers. * - ⚙️ `finish` runs exactly once after the promise settles (similar to `finish`). * @template OnSuccess - The type of the fulfilled value. * @template OnError - The type of the rejection reason, defaults to `unknown`. * @example * ```ts * import type { CustomPromiseType } from "@rzl-zone/ts-types-plus"; * import { CustomPromise } from "@rzl-zone/utils-js/promises"; * * const fetchUser = (): CustomPromiseType => * new CustomsPromise((resolve, reject) => { * apiCall().then(resolve).catch(reject); * }); * * fetchUser() * .then(user => console.log(user)) * .catch(err => console.error(err)) * .finish((result, error) => { * console.log("always runs", { result, error }); * }); * ``` */ type CustomPromiseType = CustomPromiseLike; /** ------------------------------------------------------- * * ***Utility Type: `ReadonlyOnly`.*** * ------------------------------------------------------- * **Makes the specified keys `K` of an object type `T` readonly, * while leaving the other properties mutable.** * @template T - The object type. * @template K - Keys of `T` to make readonly. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * type T0 = ReadonlyOnly<{ a: string; b: number }, 'a'>; * // ➔ { readonly a: string; b: number } * * type T1 = ReadonlyOnly<{ x: boolean; y: number; z: string }, 'y' | 'z'>; * // ➔ { x: boolean; readonly y: number; readonly z: string } * ``` */ type ReadonlyOnly = Prettify> & { readonly [P in K]: T[P] }, PrettifyOptions$3>; /** ------------------------------------------------------- * * ***Utility Type: `ReadonlyExcept`.*** * ------------------------------------------------------- * **Makes all properties of an object type `T` readonly, * except for the specified keys `K` which remain mutable.** * @template T - The object type. * @template K - Keys of `T` to remain mutable. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * type T0 = ReadonlyExcept<{ a: string; b: number }, 'a'>; * // ➔ { a: string; readonly b: number } * * type T1 = ReadonlyExcept<{ x: boolean; y: number; z: string }, 'x' | 'z'>; * // ➔ { x: boolean; readonly y: number; z: string } * ``` */ type ReadonlyExcept = Prettify & { readonly [P in Exclude]: T[P] }, PrettifyOptions$4>; /** `ReadonlyDeep` helper */ type Builtin = Primitive | AnyFunction | Date | RegExp | Error; /** `ReadonlyDeep` helper */ type _ReadonlyDeep = T extends Builtin ? T : T extends Promise ? Promise<_ReadonlyDeep> : T extends Map ? ReadonlyMap<_ReadonlyDeep, _ReadonlyDeep> : T extends WeakMap ? WeakMap<_ReadonlyDeep, _ReadonlyDeep> : T extends Set ? ReadonlySet<_ReadonlyDeep> : T extends WeakSet ? WeakSet<_ReadonlyDeep> : T extends readonly [infer A, ...infer B] ? readonly [_ReadonlyDeep, ...{ [K in keyof B]: _ReadonlyDeep }] : T extends ReadonlyArray ? ReadonlyArray<_ReadonlyDeep> : T extends object ? { readonly [K in keyof T]: _ReadonlyDeep } : T; /** ------------------------------------------------------- * * ***Utility Type: `ReadonlyDeep`.*** * ------------------------------------------------------- * **Recursively converts a type `T` into a deeply readonly structure.** * * All nested properties become immutable, including objects, * arrays, tuples, maps, sets, and promises. * * Built-in types such as primitives, functions, `Date`, `RegExp`, * and `Error` are preserved as-is. * * @template T - The type to transform into a deeply readonly type. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * * @example * ```ts * type T0 = ReadonlyDeep<{ * user: { * name: string * roles: string[] * } * }> * * // ➔ { * // readonly user: { * // readonly name: string * // readonly roles: readonly string[] * // } * // } * * type T1 = ReadonlyDeep<{ * cache: Map * }> * * // ➔ { * // readonly cache: ReadonlyMap * // } * ``` */ type ReadonlyDeep = Prettify<_ReadonlyDeep, PrettifyOptions$6>; /** ------------------------------------------------------- * * ***Utility Type: `RemoveIndexSignature`.*** * ------------------------------------------------------- * **Removes **index signatures** (e.g., `[key: string]: any`) from an object * type `T`, leaving only explicitly declared properties.** * @template T - The object type to process. * @example * ```ts * type Case1 = RemoveIndexSignature<{ [key: string]: number | string; a: string }>; * // ➔ { a: string } * * type Case2 = RemoveIndexSignature<{ x: number; y: boolean }>; * // ➔ { x: number; y: boolean } * * type Case3 = RemoveIndexSignature<{ [key: string]: number }>; * // ➔ {} // all keys were index signatures * ``` */ type RemoveIndexSignature = { [Key in keyof T as Key extends `${infer _}` ? Key : never]: T[Key] }; /** ------------------------------------------------------- * * ***Utility Type: `Replace`.*** * ------------------------------------------------------- * **Replaces the **first occurrence** of a substring (`Pivot`) * inside a string (`T`) with another substring (`ReplaceBy`).** * @template T - The source string. * @template Pivot - The substring to replace. * @template ReplaceBy - The substring that replaces `Pivot`. * @example * ```ts * type Case1 = Replace<'remove me me', 'me', 'him'>; * // ➔ 'remove him me' * type Case2 = Replace<'remove me me', 'us', 'him'>; * // ➔ 'remove me me' * type Case3 = Replace<'aaaa', 'a', 'b'>; * // ➔ 'baaa' * type Case4 = Replace<'hello', 'x', 'y'>; * // ➔ 'hello' (no match found) * ``` */ type Replace = T extends `${infer A}${Pivot}${infer B}` ? `${A}${ReplaceBy}${B}` : T; /** -------------------------------------------------- * * ***Utility Type: `ReplaceToPartial`.*** * -------------------------------------------------- * **Replaces specified keys in a type with a new value type, making them optional.** * - ✅ Useful when certain properties in a type should allow partial overrides * while keeping the rest of the structure intact. * @template TypeToBeChecked - The original object type. * @template KeyToBeReplaced - The keys in the original type to be replaced. * @template NewValueToUse - The new type to assign to the replaced keys. * @example * ```ts * type A = { name: string; age: number }; * type B = ReplaceToPartial; * // ➔ { name: string; age?: string } * ``` */ type ReplaceToPartial = Identity> & { [P in KeyToBeReplaced]?: NewValueToUse }>; /** -------------------------------------------------- * * ***Utility Type: `ReplaceToRequired`.*** * -------------------------------------------------- * **Replaces specified keys in a type with a new value type, making them required.** * - ✅ Useful when redefining a property’s type while ensuring it's required. * @template TypeToBeChecked - The original object type. * @template KeyToBeReplaced - The keys in the original type to be replaced. * @template NewValueToUse - The new type to assign to the replaced keys. * @example * ```ts * type A = { name?: string | string[]; age: number }; * type B = ReplaceToRequired; * // ➔ { name: string; age: number } * ``` */ type ReplaceToRequired = Identity> & { [P in KeyToBeReplaced]: NewValueToUse }>; /** Internal Helper */ /** Remove duplicate `undefined` from a type */ type CleanOptional = [T] extends [undefined] ? undefined : T; /** ------------------------------------------------------- * * ***Utility Type: `RequiredOnly`.*** * ------------------------------------------------------- * **Make only the specified properties in `T` **required**, while keeping the rest unchanged (remain optional if optional).** * @template T - The object type to transform. * @template K - Keys of `T` that should become required. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * // Only "a" is required, "b" and "c" remain optional * type T0 = RequiredOnly<{ a?: number; b?: string; c?: boolean }, "a">; * // ➔ { a: number; b?: string; c?: boolean } * * // Both "a" and "b" are required * type T1 = RequiredOnly<{ a?: number; b?: string; c?: boolean }, "a" | "b">; * // ➔ { a: number; b: string; c?: boolean } * * // Only "a" is required (since "x" is not a valid key of T) * type T2 = RequiredOnly<{ a?: number; b?: string; c?: boolean }, "a" | "x">; * // ➔ { a: number; b?: string; c?: boolean } * ``` * - ℹ️ ***If key is never or not in object, all properties remain unchanged:*** * ```ts * type Skip1 = RequiredOnly<{ a?: number; b?: string; c?: boolean }, "x">; * // ➔ { a?: number; b?: string; c?: boolean } * * type Skip2 = RequiredOnly<{ a?: number; b?: string; c?: boolean }, never>; * // ➔ { a?: number; b?: string; c?: boolean } * ``` */ type RequiredOnly = IsNever extends true ? T : PrettifyUnionIntersection<{ [P in Exclude]?: CleanOptional } & { [P in Extract]-?: NonUndefined> }, PrettifyOptions$1>; /** ------------------------------------------------------- * * ***Utility Type: `RequiredExcept`.*** * ------------------------------------------------------- * **Make **all properties** in `T` required, except the specified keys which remain optional.** * @template T - The object type to transform. * @template K - Keys of `T` that should remain optional. * @template PrettifyOptions - Options controlling whether the resulting * type should be normalized using the `Prettify` helper. * @example * ```ts * // All required except "a" * type T0 = RequiredExcept<{ a?: number; b?: string; c?: boolean }, "a">; * // ➔ { a?: number; b: string; c: boolean } * * // All required except "a" and "b" * type T1 = RequiredExcept<{ a?: number; b?: string; c?: boolean }, "a" | "b">; * // ➔ { a?: number; b?: string; c: boolean } * * // Only "a" remains optional (since "x" is not a valid key of T) * type T2 = RequiredExcept<{ a?: number; b?: string; c?: boolean }, "a" | "x">; * // ➔ { a?: number; b: string; c: boolean } * ``` * * - ℹ️ ***If key is never or not in object, all properties become required:*** * ```ts * type Skip1 = RequiredExcept<{ a?: number; b?: string; c?: boolean }, "x">; * // ➔ { a: number; b: string; c: boolean } * * type Skip2 = RequiredExcept<{ a?: number; b?: string; c?: boolean }, never>; * // ➔ { a: number; b: string; c: boolean } * ``` */ type RequiredExcept = IsNever extends true ? Required : PrettifyUnionIntersection<{ [P in Exclude]-?: NonUndefined> } & { [P in Extract]?: CleanOptional }, PrettifyOptions$2>; type _Reverse = T extends readonly [infer First, ...infer Rest] ? _Reverse : Result; type FilterByType$1 = T extends readonly [infer Head, ...infer Tail] ? Head extends U ? [Head, ...FilterByType$1] : FilterByType$1 : []; type Grouped = [...FilterByType$1, ...FilterByType$1, ...FilterByType$1, ...FilterByType$1>]; type MaybeReadonly = IsTuple extends true ? IsReadonlyArray extends true ? Readonly : R : R; /** ------------------------------------------------------- * * ***Utility Type: `Reverse`.*** * ------------------------------------------------------- * **Returns a new tuple or readonly array type with the elements in reverse order.** * - **Behavior:** * 1. **Tuple**: The reversed result preserves tuple properties, * including `readonly` if applicable. * - Elements are **grouped in this order before reversing**: * `number`, `string`, `boolean`, then any other types. * 2. **Normal array (non-tuple)**: The type is returned as-is (no reversal). * - ℹ️ **Notes:** * - Supports arbitrary types in the tuple, including objects, Date, symbol, etc. * - Grouping ensures that numbers, strings, and booleans are reversed in logical * groups, while other types remain at the end in their original order before * reverse. * @template T - The array or tuple type to reverse. * @example * ```ts * // Mutable tuple of numbers * type T0 = Reverse<[1, 2, 3]>; * // Grouped: [1,2,3] (numbers first) * // Reversed: [3, 2, 1] * * // Readonly tuple of numbers * type T1 = Reverse; * // Grouped: [1,2,3] * // Reversed: readonly [3, 2, 1] * * // Tuple of strings * type T2 = Reverse<["a", "b", "c"]>; * // Grouped: ["a","b","c"] * // Reversed: ["c","b","a"] * * // Readonly tuple of strings * type T3 = Reverse; * // Grouped: ["x","y","z"] * // Reversed: readonly ["z","y","x"] * * // Tuple of mixed types (numbers, strings, booleans) * type T4 = Reverse<[1, "a", true, 2, "b", false]>; * // Grouped: [1,2,"a","b",true,false] * // Reversed: [false,"b","a",2,1,true] * * // Readonly tuple of mixed types * type T5 = Reverse; * // Grouped: [2,"b","x",false,true] * // Reversed: readonly [true,false,"x","b",2] * * // Tuple with arbitrary types (Date, object, symbol, bigint, etc.) * type T6 = Reverse<[1, "a", true, 2, "b", false, Date, {x:1}, symbol, 10n]>; * // Grouped: [1,2,"a","b",true,false,Date,{x:1},symbol,10n] * // Reversed: [10n,symbol,{x:1},Date,false,true,"b","a",2,1] * * // Normal arrays (not tuples) remain unchanged * type T7 = Reverse; * // ➔ number[] * * type T8 = Reverse; * // ➔ string[] * * type T9 = Reverse<(number | string)[]>; * // ➔ (string | number)[] * * type T10 = Reverse<(boolean | number | string)[]>; * // ➔ (string | number | boolean)[] * ``` */ type Reverse = T extends readonly [unknown, ...unknown[]] ? _Reverse> extends infer R extends readonly unknown[] ? MaybeReadonly : never : T; /** ------------------------------------------------------- * * ***Utility Type: `Round`.*** * ------------------------------------------------------- * **Type-level version of `Math.round()`. * Returns the value of a number rounded to the **nearest integer**.** * - **Behavior:** * - If `T` is a float, it rounds to the nearest whole number: * - Fraction `≥ 0.5` ➔ rounds up. * - Fraction `< 0.5` ➔ rounds down. * - If `T` is already an integer, it returns `T` as-is. * @template T - The number type to round. * @example * ```ts * // Positive float * type T0 = Round<3.14>; * // ➔ 3 * * // Negative float * type T1 = Round<-3.14>; * // ➔ -3 * * // Fraction ≥ 0.5 * type T2 = Round<2.6>; * // ➔ 3 * * // Already integer * type T3 = Round<5>; * // ➔ 5 * ``` */ type Round = IsFloat extends true ? GetFloatNumberParts extends [infer Whole extends number, infer Fraction extends number] ? IsGreaterThan, 4> extends true ? Increment : Whole : never : T; type SliceRemovedItemValue = Record<"__type-rzl_internal__", symbol>; type FilterRemoved = T extends readonly [infer First, ...infer Rest extends unknown[]] ? FilterRemoved> : Result; /** ------------------------------------------------------- * * ***Utility Type: `Slice`.*** * ------------------------------------------------------- * **Type-level version of `Array.prototype.slice()`.** * @description * Returns a shallow copy of a portion of an array, selected from `Start` to `End` (not including `End`). * - **Behavior:** * - `Start` defaults to `0`. * - `End` defaults to `T["length"]`. * - Negative indices are interpreted as `T["length"] + index`. * - If `Start >= T["length"]` or `End <= Start`, returns an empty array `[]`. * - If the full range is selected, returns `T` as-is. * @template T - The array type to slice. * @template Start - The start index (inclusive). Defaults to `0`. * @template End - The end index (exclusive). Defaults to `T["length"]`. * @example * ```ts * // Slice from index 1 to end * type T0 = Slice<[1, 2, 3, 4], 1>; * // ➔ [2, 3, 4] * * // Slice from index 1 to 3 * type T1 = Slice<[1, 2, 3, 4], 1, 3>; * // ➔ [2, 3] * * // Slice with negative start * type T2 = Slice<[1, 2, 3, 4], -2>; * // ➔ [3, 4] * * // Slice with negative end * type T3 = Slice<[1, 2, 3, 4], 1, -1>; * // ➔ [2, 3] * * // Slice exceeding array length * type T4 = Slice<[1, 2, 3], 0, 10>; * // ➔ [1, 2, 3] * * // Slice resulting in empty array * type T5 = Slice<[1, 2, 3], 3, 2>; * // ➔ [] * ``` */ type Slice = (IsEmptyArray extends true ? "self" : IsGreaterOrEqual extends true ? "empty" : IsNegative extends true ? IsGreaterOrEqual, T["length"]> extends true ? "empty" : [IfPositive>, Sum] : And, IsGreaterOrEqual, T["length"]>>, IsGreaterOrEqual> extends true ? "self" : [IfPositive>, End]) extends infer Indexes ? Indexes extends "self" ? T : Indexes extends "empty" ? [] : Indexes extends [infer NewStart extends number, infer NewEnd extends number] ? IfGreaterOrEqual extends true ? [] : FilterRemoved<{ [K in keyof T]: IsArrayIndex extends true ? If, NewStart>, IsLowerThan, NewEnd>>, T[K], SliceRemovedItemValue> : T[K] }> : T : T; /** ------------------------------------------------------- * * ***Utility Type: `Swap`.*** * ------------------------------------------------------- * **Swaps the positions of two elements in a tuple at the type level.** * - **Behavior:** * - Only works on tuple types. Non-tuple arrays are returned as-is. * - Validates that `FromIndex` and `ToIndex` are within bounds of the tuple. * - If `FromIndex` and `ToIndex` are equal, the tuple remains unchanged. * @template T - The tuple type. * @template FromIndex - The index of the first element to swap. * @template ToIndex - The index of the second element to swap. * @example * ```ts * // Swap first and last element * type Case1 = Swap<[1, 2, 3], 0, 2>; * // ➔ [3, 2, 1] * * // Swap same index (no change) * type Case2 = Swap<[1, 2, 3], 0, 0>; * // ➔ [1, 2, 3] * * // Swap middle elements * type Case3 = Swap<["a", "b", "c"], 1, 2>; * // ➔ ["a", "c", "b"] * * // Non-tuple array remains unchanged * type Case4 = Swap; * // ➔ number[] * ``` */ type Swap = IsTuple extends true ? And, IsBetween> extends true ? T[FromIndex] extends infer From ? T[ToIndex] extends infer To ? { [K in keyof T]: ParseNumber extends infer NumK ? IsEqual extends true ? To : IsEqual extends true ? From : T[K] : never } : never : never : never : T; type _SortSingle = IsEqual extends true ? Result : Increment extends infer NextCurrentIndex extends number ? _SortSingle extends true ? Swap extends infer NewResult extends readonly number[] ? NewResult : Result : Result, PivotIndex, NextCurrentIndex> : never; type _Sort = IsLowerOrEqual extends true ? T : _SortSingle extends infer NewT extends readonly number[] ? _Sort> : T; /** ------------------------------------------------------- * * ***Utility Type: `Sort`.*** * ------------------------------------------------------- * **Type-level function that sorts a **tuple of numbers** in **ascending order**.** * - **Behavior:** * - Tuples with length `< 2` are returned as-is. * - Works only on **tuple literal types**, not on general arrays (`number[]`). * @template T - Tuple of numbers to sort. * @example * ```ts * // Sort positive numbers * type T0 = Sort<[3, 2, 1]>; * // ➔ [1, 2, 3] * * // Sort numbers with negative values * type T1 = Sort<[1, -1, 0]>; * // ➔ [-1, 0, 1] * * // Already sorted * type T2 = Sort<[0, 1, 2]>; * // ➔ [0, 1, 2] * * // Single element tuple * type T3 = Sort<[42]>; * // ➔ [42] * * // Empty tuple * type T4 = Sort<[]>; * // ➔ [] * ``` */ type Sort = IsLowerThan extends true ? T : _Sort>; /** ------------------------------------------------------- * * ***Utility Type: `StartsWith`.*** * ------------------------------------------------------- * **Type-level utility that determines whether a string `Str` * starts with the substring `Pivot`.** * - **Behavior:** * - Supports `Pivot` as either `string` or `number`. * - Returns `true` if `Str` starts with `Pivot`, otherwise `false`. * @template Str - The string to check. * @template Pivot - The substring or number to check as the prefix. * @example * ```ts * // Check string prefix * type Case1 = StartsWith<'abc', 'a'>; * // ➔ true * * type Case2 = StartsWith<'abc', 'b'>; * // ➔ false * * // Check numeric prefix * type Case3 = StartsWith<'123', 1>; * // ➔ true * * type Case4 = StartsWith<'123', 2>; * // ➔ false * * // Multi-character pivot * type Case5 = StartsWith<'typescript', 'type'>; * // ➔ true * * type Case6 = StartsWith<'typescript', 'script'>; * // ➔ false * ``` */ type StartsWith = Str extends `${Pivot}${string}` ? true : false; /** ------------------------------------------------------- * * ***Utility Type: `Switch`.*** * ------------------------------------------------------- * **Type-level version of a `switch` statement.** * - **Behavior:** * - Checks if `Condition` exists as a key in `Cases`. * - Returns the corresponding value if the key exists. * - Returns `Default` if the key does not exist. * @template Condition - The value to match against case keys. * @template Cases - An object mapping keys to corresponding values. * @template Default - The default value returned if `Condition` is not a key in `Cases` (defaults to `never`). * @example * ```ts * const a = 'const'; * * // Matches 'const' key ➔ 'bar' * type Result1 = Switch; * // ➔ 'bar' * * // Condition not present ➔ returns default * type Result2 = Switch<'other', { number: 'foo', const: 'bar' }, 'default'>; * // ➔ 'default' * * // Condition present but no default specified * type Result3 = Switch<'number', { number: 'foo', const: 'bar' }>; * // ➔ 'foo' * ``` */ type Switch, Default = never> = Condition extends keyof Cases ? Cases[Condition] : Default; /** ------------------------------------------------------- * * ***Utility Type: `ToPrimitive`.*** * ------------------------------------------------------- * **Converts a literal type to its corresponding primitive type.** * - **Behavior:** * - `string literal` ➔ `string`. * - `number literal` ➔ `number`. * - `boolean literal` ➔ `boolean`. * - `bigint literal` ➔ `bigint`. * - `symbol literal` ➔ `symbol`. * - `null` ➔ `null`. * - `undefined` ➔ `undefined`. * - Objects ➔ recursively converts all properties to their primitive types. * @template T - The literal type to convert to a primitive type. * @example * ```ts * // Number literal * type Case1 = ToPrimitive<1>; * // ➔ number * * // String literal * type Case2 = ToPrimitive<'1'>; * // ➔ string * * // Boolean literal * type Case3 = ToPrimitive; * // ➔ boolean * * // BigInt literal * type Case4 = ToPrimitive<123n>; * // ➔ bigint * * // Symbol literal * type Case5 = ToPrimitive; * // ➔ symbol * * // Null and undefined * type Case6 = ToPrimitive; * // ➔ null * type Case7 = ToPrimitive; * // ➔ undefined * * // Object with literal properties * type Case8 = ToPrimitive<{ a: 1; b: 's'; c: true }>; * // ➔ { a: number; b: string; c: boolean } * ``` */ type ToPrimitive = T extends string ? string : T extends number ? number : T extends null ? null : T extends undefined ? undefined : T extends boolean ? boolean : T extends bigint ? bigint : T extends symbol ? symbol : { [K in keyof T]: ToPrimitive }; /** ------------------------------------------------------- * * ***Utility Type: `Trunc`.*** * ------------------------------------------------------- * **Type version of `Math.trunc()`.** * @description * Returns the **integer part** of a number by removing any fractional digits. * - **Behavior:** * - If `T` is a floating-point number, returns the integer part. * - Preserves the sign for negative numbers. * - If `T` is already an integer, returns `T`. * - If `T` is `number` (general type), returns `T`. * @template T - The number type to truncate. * @example * ```ts * // Positive float * type T0 = Trunc<3.14>; * // ➔ 3 * * // Negative float * type T1 = Trunc<-3.14>; * // ➔ -3 * * // Already integer * type T2 = Trunc<42>; * // ➔ 42 * * // General number type * type T3 = Trunc; * // ➔ number * ``` */ type Trunc = number extends T ? T : IsFloat extends true ? GetFloatNumberParts[0] extends infer IntegerPart extends number ? IsNegative extends true ? Negate : IntegerPart : never : T; type FilterByType = T extends readonly [infer Head, ...infer Tail] ? Head extends U ? [Head, ...FilterByType] : FilterByType : []; type GroupedKeys = [...FilterByType, ...FilterByType, ...FilterByType]; /** ------------------------------------------------------- * * ***Utility Type: `TupleToObject`.*** * ------------------------------------------------------- * **Accepts a tuple of `string`, `number`, or `symbol` and returns an object type * where each key **and its value** are the elements of the tuple.** * - **Behavior:** * - Tuple elements must extend `PropertyKey` (`string | number | symbol`). * - The resulting object has keys and values identical to the tuple elements. * @template T - The tuple of property keys. * @example * ```ts * // Tuple of strings * type T0 = TupleToObject<['foo', 'bar']>; * // ➔ { foo: 'foo'; bar: 'bar' } * * // Tuple of numbers * type T1 = TupleToObject<[1, 2, 3]>; * // ➔ { 1: 1; 2: 2; 3: 3 } * * // Tuple of mixed property keys * type T2 = TupleToObject<['a', 0, symbol]>; * // ➔ { [x: symbol]: symbol; 0: 0; a: 'a'; } * ``` */ type TupleToObject = { [K in GroupedKeys[number]]: K }; /** ------------------------------------------------------- * * ***Utility Type: `Unshift`.*** * ------------------------------------------------------- * **Adds the specified element `U` to the **beginning** of the tuple/array `T`.** * @template T - The original tuple or array. * @template U - The element to add at the start. * @example * ```ts * // Adding string to a tuple * type Case1 = Unshift<['bar'], 'foo'>; * // ➔ ['foo', 'bar'] * * // Adding number to an empty array * type Case2 = Unshift<[], 1>; * // ➔ [1] * ``` */ type Unshift = [U, ...T]; export type { Abs, AnObjectNonArray, And, AndArr, AnifyProperties, AnifyPropertiesOptions, AnyFunction, AnyRecord, AnyString, AnyStringRecord, AreAnagrams, ArgumentTypes, ArrayElementType, Arrayable, Awaitable, BoxedPrimitivesTypes, Ceil, CharAt, Color, ColorCssNamed, ColorOptions, CompareNumberLength, CompareStringLength, Concat, CustomPromiseType, DataTypes, Decrement, DeepMergeArrayUnion, DeepReplaceType, DefaultColorOptions, DefaultHSLOptions, DefaultNumberLengthOptions, DefaultPathToFieldsOptions, DefaultPrettifyOptions, DefaultRGBOptions, DigitsTuple, Div, Dot, DotArray, EmptyArray, EmptyString, EndsWith, Even, EvenDigit, ExcludeStrict, Extends, ExtendsArr, ExtractStrict, Factorial, Fibonacci, FirstCharacter, FirstCharacterOptions, FirstDigit$1 as FirstDigit, FixNeverArrayRecursive, Float, Floor, GetArrayElementType, GetFloatNumberParts, HEX, HSL, HSLOptions, Identity, If, IfAny, IfColor, IfEmptyArray, IfEmptyString, IfEqual, IfEven, IfExtends, IfFloat, IfGreaterOrEqual, IfGreaterThan, IfHEX, IfHSL, IfInteger, IfLowerOrEqual, IfLowerThan, IfNegative, IfNegativeFloat, IfNegativeInteger, IfNever, IfNonEmptyArray, IfNonEmptyString, IfNot, IfNotEqual, IfNotExtends, IfOdd, IfPositive, IfPositiveFloat, IfPositiveInteger, IfRGB, IfTuple, IfUnknown, Includes, Increment, IndexOf, Integer, IntlObjects, IsAny, IsArray, IsArrayIndex, IsArrayOrTuple, IsBaseType, IsBetween, IsBetweenOptions, IsColor, IsConstructor, IsDivisible, IsDivisibleByFive, IsDivisibleByHundred, IsDivisibleBySix, IsDivisibleByTen, IsDivisibleByThree, IsDivisibleByTwo, IsEmptyArray, IsEmptyString, IsEqual, IsEven, IsExactly, IsFloat, IsFunction, IsGreaterOrEqual, IsGreaterThan, IsHEX, IsHSL, IsInteger, IsLetter, IsLongerNumber, IsLongerString, IsLowerOrEqual, IsLowerThan, IsMutableArray, IsNegative, IsNegativeFloat, IsNegativeInteger, IsNever, IsNewable, IsNonEmptyArray, IsNonEmptyString, IsNotEqual, IsOdd, IsPalindrome, IsPositive, IsPositiveFloat, IsPositiveInteger, IsPrimitive, IsRGB, IsReadonlyArray, IsRealPrimitive, IsSameLengthNumber, IsSameLengthString, IsScientificNumber, IsShorterNumber, IsShorterString, IsStringLiteral, IsTuple, IsUnion, IsUnknown, Join, KeepNil, KeepNull, KeepUndef, LastCharacter, LastCharacterOptions, LooseLiteral, Max, MaxArr, Min, MinArr, Mod, Multi, Mutable, MutableArray, MutableExcept, MutableOnly, MutableOptions, Negate, Negative, NegativeFloat, NegativeInteger, NeverifyProperties, NeverifyPropertiesOptions, Nilable, NonEmptyArray, NonEmptyString, NonNil, NonNull, NonNullableObject, NonNullableObjectExcept, NonNullableObjectOnly, NonPlainObject, NonUndefined, NormalizeEmptyArraysRecursive, Not, NotExtends, NullToUndefined, Nullable, Nullish, NumberLength, NumberRangeLimit, NumberRangeUnion, Odd, OddDigit, OmitStrict, Or, OrArr, OverrideTypes, ParseNumber, ParseScientificNumber, PartialExcept, PartialOnly, PathToFields, PathToFieldsOptions, PickStrict, Pop, PopOptions, Positive, PositiveFloat, PositiveInteger, Pow, Prettify, PrettifyOptions, PrettifyUnionIntersection, Primitive, Push, RGB, RGBOptions, ReadonlyDeep, ReadonlyExcept, ReadonlyOnly, RemoveEmptyArrayElements, RemoveIndexSignature, RemoveLeading, Repeat, Replace, ReplaceAll, ReplaceToPartial, ReplaceToRequired, RequiredExcept, RequiredOnly, ReturnItselfIfExtends, ReturnItselfIfNotExtends, Reverse, Round, Shift, ShiftOptions, Slice, Sort, Split, StartsWith, StrictAwaitable, StringLength, Stringify, Sub, Sum, SumArr, Swap, Switch, ToPrimitive, Trim, TrimLeft, TrimRight, TrimsLower, TrimsUpper, Trunc, TupleToObject, TypeNumberLengthOptions, TypedArray, Undefinedable, UnionToIntersection, UnknownRecord, UnknownifyProperties, UnknownifyPropertiesOptions, Unshift, ValueOf, ValueOfArray, ValueOfExcept, ValueOfOnly, WebApiObjects, Whitespace, WordSeparator };