// ============================================================================ // Primitives // ============================================================================ /** * @description 表示既保留字面量自动补全体验,又允许回退到任意字符串的字符串类型。 */ export type StringAutoCompletable = string & {} /** * @description 为一组选项字符串补充自动补全,同时允许传入其它字符串。 * * @see {@link https://x.com/mattpocockuk/status/1822917991232569660} */ export type StringWithAutoCompleteOptions = Options | StringAutoCompletable /** * @description Define the uppercase letter type. * * @example * ``` * // Expect: 'A' | 'B' | ... | 'Z' * type Example1 = UppercaseLetter * ``` */ export type UppercaseLetter = | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" /** * @description Define the lowercase letter type. * * @example * ``` * // Expect: 'a' | 'b' | ... | 'z' * type Example1 = LowercaseLetter * ``` */ export type LowercaseLetter = | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" /** * @description Define the digit character type. * * @example * ``` * // Expect: '0' | '1' | ... | '9' * type Example1 = DigitCharacter * ``` */ export type DigitCharacter = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" /** * @description Define the alphanumeric character type. * * @example * ``` * // Expect: 'a' | 'b' | ... | 'z' | 'A' | 'B' | ... | 'Z' | '0' | '1' | ... | '9' * type Example1 = Alphanumeric * ``` */ export type AlphanumericCharacter = UppercaseLetter | LowercaseLetter | DigitCharacter // ============================================================================ // Validation // ============================================================================ /** * @description Check if a string only contains digits. * * @example * ``` * // Expect: true * type Example1 = StringIsNumber<'123'> * // Expect: false * type Example2 = StringIsNumber<'12a'> * ``` */ export type StringIsNumber = S extends "" ? false : S extends `${infer First}${infer Rest}` ? First extends "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ? Rest extends "" ? true : StringIsNumber : false : false /** * @description Check if a string is all lowercase. * * @example * ``` * // Expect: true * type Example1 = StringIsLowerCase<'hello'> * // Expect: false * type Example2 = StringIsLowerCase<'Hello'> * ``` */ export type StringIsLowerCase = S extends Lowercase ? true : false /** * @description Check if a string is all uppercase. * * @example * ``` * // Expect: true * type Example1 = StringIsUpperCase<'HELLO'> * // Expect: false * type Example2 = StringIsUpperCase<'Hello'> * ``` */ export type StringIsUpperCase = S extends Uppercase ? true : false /** * @description Check if a string only contains alphabetic characters. * * @example * ``` * // Expect: true * type Example1 = StringIsAlpha<'hello'> * // Expect: false * type Example2 = StringIsAlpha<'hello123'> * ``` */ export type StringIsAlpha = S extends "" ? false : S extends `${infer First}${infer Rest}` ? First extends Uppercase ? First extends Lowercase ? false : Rest extends "" ? true : StringIsAlpha : Rest extends "" ? true : StringIsAlpha : false /** * @description Check if a string only contains whitespace characters. * * @example * ``` * // Expect: true * type Example1 = StringIsWhitespace<' '> * // Expect: false * type Example2 = StringIsWhitespace<' a '> * ``` */ export type StringIsWhitespace = S extends "" ? true : S extends `${infer First}${infer Rest}` ? First extends " " | "\n" | "\t" | "\r" ? StringIsWhitespace : false : false /** * @description Check if a string is empty. * * @example * ``` * // Expect: true * type Example1 = StringIsEmpty<''> * ``` */ export type StringIsEmpty = S extends "" ? true : false // ============================================================================ // Comparison // ============================================================================ /** * @description Check if two strings are equal. * * @example * ``` * // Expect: true * type Example1 = StringIsEqual<'hello', 'hello'> * // Expect: false * type Example2 = StringIsEqual<'hello', 'world'> * ``` */ export type StringIsEqual = S1 extends S2 ? S2 extends S1 ? true : false : false /** * @description Check if a string starts with a prefix. * * @example * ``` * // Expect: true * type Example1 = StringStartsWith<'hello world', 'hello'> * ``` */ export type StringStartsWith< S extends string, Prefix extends string, > = S extends `${Prefix}${string}` ? true : false /** * @description Check if a string ends with a suffix. * * @example * ``` * // Expect: true * type Example1 = StringEndsWith<'hello world', 'world'> * ``` */ export type StringEndsWith = S extends `${string}${Suffix}` ? true : false /** * @description Check if a string includes a substring. * * @example * ``` * // Expect: true * type Example1 = StringIncludes<'hello world', 'lo wo'> * ``` */ export type StringIncludes< S extends string, Substring extends string, > = S extends `${string}${Substring}${string}` ? true : false // ============================================================================ // Query // ============================================================================ type InternalStringLength< S extends string, Acc extends readonly unknown[], > = S extends `${string}${infer Rest}` ? InternalStringLength : Acc["length"] /** * @description Get the length of a string literal type. * * @example * ``` * // Expect: 5 * type Example1 = StringLength<'hello'> * ``` */ export type StringLength = InternalStringLength type InternalStringCount< S extends string, Sub extends string, Count extends readonly unknown[] = [], > = S extends `${infer _Start}${Sub}${infer Rest}` ? InternalStringCount : Count["length"] /** * @description Count the number of occurrences of a substring. * * @example * ``` * // Expect: 2 * type Example1 = StringCount<'hello world', 'l'> * // Expect: 0 * type Example2 = StringCount<'hello', 'x'> * ``` */ export type StringCount = Sub extends "" ? 0 : InternalStringCount type InternalStringIndexOf< S extends string, Sub extends string, Index extends readonly unknown[] = [], > = S extends `${Sub}${string}` ? Index["length"] : S extends `${string}${infer Rest}` ? InternalStringIndexOf : -1 /** * @description Find the first occurrence index of a substring. * * @example * ``` * // Expect: 2 * type Example1 = StringIndexOf<'hello', 'll'> * // Expect: -1 * type Example2 = StringIndexOf<'hello', 'x'> * ``` */ export type StringIndexOf = Sub extends "" ? 0 : InternalStringIndexOf type InternalStringCommonPrefix< S1 extends string, S2 extends string, Acc extends string = "", > = S1 extends `${infer First1}${infer Rest1}` ? S2 extends `${infer First2}${infer Rest2}` ? First1 extends First2 ? InternalStringCommonPrefix : Acc : Acc : Acc /** * @description Get the common prefix of two strings. * * @example * ``` * // Expect: 'hello' * type Example1 = StringCommonPrefix<'helloworld', 'hellothere'> * ``` */ export type StringCommonPrefix = InternalStringCommonPrefix< S1, S2 > // ============================================================================ // String Generation // ============================================================================ type InternalRepeat< S extends string, N extends number, Acc extends string, Count extends readonly unknown[], > = Count["length"] extends N ? Acc : InternalRepeat /** * @description Repeat a string N times. * * @example * ``` * // Expect: 'ababab' * type Example1 = StringRepeat<'ab', 3> * ``` */ export type StringRepeat = InternalRepeat // ============================================================================ // Extraction // ============================================================================ /** * @description Extract the first character of a string. * * @example * ``` * // Expect: 'h' * type Example1 = StringFirst<'hello'> * ``` */ export type StringFirst = S extends `${infer First}${string}` ? First : never /** * @description Extract the last character of a string. * * @example * ``` * // Expect: 'o' * type Example1 = StringLast<'hello'> * ``` */ export type StringLast = S extends `${infer Rest}${infer Last}` ? Rest extends "" ? Last : StringLast : never /** * @description Get the character at a specific index in a string. * * @example * ``` * // Expect: 'e' * type Example1 = StringAt<'hello', 1> * ``` */ export type StringAt = StringSplit extends infer Characters extends string[] ? Characters[Index] : never // ============================================================================ // Manipulation // ============================================================================ /** * @description Concatenate an array of strings. * * @example * ``` * // Expect: 'helloworld' * type Example1 = StringConcat<['hello', 'world']> * ``` */ export type StringConcat = T extends [ infer First extends string, ...infer Rest extends string[], ] ? `${First}${StringConcat}` : "" /** * @description Split a string into an array by a separator. * * @example * ``` * // Expect: ['a', 'b', 'c'] * type Example1 = StringSplit<'a,b,c', ','> * ``` */ export type StringSplit< S extends string, Separator extends string, > = S extends `${infer First}${Separator}${infer Rest}` ? [First, ...StringSplit] : S extends "" ? [] : [S] type InternalStringSplitToWords< S extends string, Acc extends string[] = [], Current extends string = "", > = S extends `${infer First}${infer Rest}` ? First extends " " | "-" | "_" ? Current extends "" ? InternalStringSplitToWords : InternalStringSplitToWords : InternalStringSplitToWords : Current extends "" ? Acc : [...Acc, Current] /** * @description Split a string into words (by spaces, hyphens, underscores). * * @example * ``` * // Expect: ['hello', 'world', 'test'] * type Example1 = StringSplitToWords<'hello-world_test'> * ``` */ export type StringSplitToWords = InternalStringSplitToWords type InternalStringSplitToChunks< S extends string, Size extends number, Acc extends string[] = [], Current extends string = "", Counter extends readonly unknown[] = [], > = Counter["length"] extends Size ? InternalStringSplitToChunks : S extends `${infer First}${infer Rest}` ? InternalStringSplitToChunks : Current extends "" ? Acc : [...Acc, Current] /** * @description Split a string into chunks of a specific size. * * @example * ``` * // Expect: ['he', 'll', 'o'] * type Example1 = StringSplitToChunks<'hello', 2> * ``` */ export type StringSplitToChunks< S extends string, Size extends number, > = InternalStringSplitToChunks /** * @description Join an array of strings with a separator. * * @example * ``` * // Expect: 'a-b-c' * type Example1 = StringJoin<['a', 'b', 'c'], '-'> * ``` */ export type StringJoin = T extends [ infer First extends string, ...infer Rest extends string[], ] ? Rest extends [] ? First : `${First}${Separator}${StringJoin}` : "" type InternalReverse< S extends string, Acc extends string = "", > = S extends `${infer First}${infer Rest}` ? InternalReverse : Acc /** * @description Reverse a string. * * @example * ``` * // Expect: 'olleh' * type Example1 = StringReverse<'hello'> * ``` */ export type StringReverse = InternalReverse type InternalStringDropFirst< S extends string, N extends number, Counter extends readonly unknown[] = [], > = Counter["length"] extends N ? S : S extends `${string}${infer Rest}` ? InternalStringDropFirst : S /** * @description Drop the first N characters from a string. * * @example * ``` * // Expect: 'lo' * type Example1 = StringDropFirst<'hello', 3> * ``` */ export type StringDropFirst = InternalStringDropFirst type InternalStringDropLast< S extends string, N extends number, Counter extends readonly unknown[] = [], > = Counter["length"] extends N ? S : S extends `${infer Rest}${string}` ? InternalStringDropLast : S /** * @description Drop the last N characters from a string. * * @example * ``` * // Expect: 'hel' * type Example1 = StringDropLast<'hello', 2> * ``` */ export type StringDropLast = InternalStringDropLast type InternalStringTakeFirst< S extends string, N extends number, Acc extends string = "", Counter extends readonly unknown[] = [], > = Counter["length"] extends N ? Acc : S extends `${infer First}${infer Rest}` ? InternalStringTakeFirst : Acc /** * @description Take the first N characters from a string. * * @example * ``` * // Expect: 'hel' * type Example1 = StringTakeFirst<'hello', 3> * ``` */ export type StringTakeFirst = InternalStringTakeFirst type InternalStringTakeLast< S extends string, N extends number, Counter extends readonly unknown[] = [], > = Counter["length"] extends N ? S : S extends `${string}${infer Rest}` ? InternalStringTakeLast : "" /** * @description Take the last N characters from a string. * * @example * ``` * // Expect: 'lo' * type Example1 = StringTakeLast<'hello', 2> * ``` */ export type StringTakeLast = InternalStringTakeLast /** * @description Replace the first occurrence of a substring with another. * * @example * ``` * // Expect: 'hello typescript world' * type Example1 = StringReplaceFirst<'hello world world', 'world', 'typescript'> * ``` */ export type StringReplaceFirst< S extends string, From extends string, To extends string, > = From extends "" ? S : S extends `${infer Start}${From}${infer Rest}` ? `${Start}${To}${Rest}` : S /** * @description Replace all occurrences of a substring with another. * * @example * ``` * // Expect: 'hello typescript typescript' * type Example1 = StringReplaceAll<'hello world world', 'world', 'typescript'> * ``` */ export type StringReplaceAll< S extends string, From extends string, To extends string, > = From extends "" ? S : S extends `${infer Start}${From}${infer Rest}` ? `${Start}${To}${StringReplaceAll}` : S type InternalStringInsert< S extends string, Index extends number, Insert extends string, Counter extends readonly unknown[] = [], Acc extends string = "", > = Counter["length"] extends Index ? `${Acc}${Insert}${S}` : S extends `${infer First}${infer Rest}` ? InternalStringInsert : `${Acc}${Insert}` /** * @description Insert a string at a specific index. * * @example * ``` * // Expect: 'helXYZlo' * type Example1 = StringInsert<'hello', 3, 'XYZ'> * ``` */ export type StringInsert< S extends string, Index extends number, Insert extends string, > = InternalStringInsert type InternalStringRemove< S extends string, Start extends number, End extends number, Counter extends readonly unknown[] = [], Acc extends string = "", > = S extends `${infer First}${infer Rest}` ? Counter["length"] extends Start ? InternalStringRemoveRange : InternalStringRemove : Acc type InternalStringRemoveRange< S extends string, End extends number, Start extends number, Counter extends readonly unknown[], > = Counter["length"] extends End ? S : S extends `${string}${infer Rest}` ? InternalStringRemoveRange : "" /** * @description Remove characters from a string between start and end indices. * * @example * ``` * // Expect: 'heo' * type Example1 = StringRemove<'hello', 2, 4> * ``` */ export type StringRemove< S extends string, Start extends number, End extends number, > = InternalStringRemove /** * @description Trim whitespace from both ends of a string. * * @example * ``` * // Expect: 'hello' * type Example1 = StringTrim<' hello '> * ``` */ export type StringTrim = S extends | ` ${infer Rest}` | `\n${infer Rest}` | `\t${infer Rest}` ? StringTrim : S extends `${infer Rest} ` | `${infer Rest}\n` | `${infer Rest}\t` ? StringTrim : S /** * @description Trim whitespace from the start of a string. * * @example * ``` * // Expect: 'hello' * type Example1 = StringTrimStart<' hello'> * ``` */ export type StringTrimStart = S extends | ` ${infer Rest}` | `\n${infer Rest}` | `\t${infer Rest}` ? StringTrimStart : S /** * @description Trim whitespace from the end of a string. * * @example * ``` * // Expect: 'hello' * type Example1 = StringTrimEnd<'hello '> * ``` */ export type StringTrimEnd = S extends | `${infer Rest} ` | `${infer Rest}\n` | `${infer Rest}\t` ? StringTrimEnd : S type InternalStringPadStart< S extends string, Length extends number, Fill extends string, Acc extends string, Count extends readonly unknown[], > = StringLength extends Length ? Acc : InternalStringPadStart /** * @description Pad a string on the left to a target length with a fill string. * * @example * ``` * // Expect: '005' * type Example1 = StringPadStart<'5', 3, '0'> * ``` */ export type StringPadStart< S extends string, Length extends number, Fill extends string = " ", > = InternalStringPadStart type InternalStringPadEnd< S extends string, Length extends number, Fill extends string, Acc extends string, Count extends readonly unknown[], > = StringLength extends Length ? Acc : InternalStringPadEnd /** * @description Pad a string on the right to a target length with a fill string. * * @example * ``` * // Expect: '500' * type Example1 = StringPadEnd<'5', 3, '0'> * ``` */ export type StringPadEnd< S extends string, Length extends number, Fill extends string = " ", > = InternalStringPadEnd /** * @description Convert a string to uppercase. * * @example * ``` * // Expect: 'HELLO' * type Example1 = StringUppercase<'hello'> * ``` */ export type StringUppercase = Uppercase /** * @description Convert a string to lowercase. * * @example * ``` * // Expect: 'hello' * type Example1 = StringLowercase<'HELLO'> * ``` */ export type StringLowercase = Lowercase /** * @description Capitalize the first letter of a string. * * @example * ``` * // Expect: 'Hello' * type Example1 = StringCapitalize<'hello'> * ``` */ export type StringCapitalize = S extends `${infer First}${infer Rest}` ? `${Uppercase}${Rest}` : S /** * @description Uncapitalize the first letter of a string. * * @example * ``` * // Expect: 'hello' * type Example1 = StringUncapitalize<'Hello'> * ``` */ export type StringUncapitalize = S extends `${infer First}${infer Rest}` ? `${Lowercase}${Rest}` : S /** * @description Convert a string to kebab-case. * * @example * ``` * // Expect: 'hello-world' * type Example1 = StringKebabCase<'helloWorld'> * // Expect: 'hello-world' * type Example2 = StringKebabCase<'HelloWorld'> * // Expect: 'hello-world--test' * type Example3 = StringKebabCase<'helloWorld-Test'> * // Expect: 'u-r-l-string' * type Example4 = StringKebabCase<'URLString'> * ``` */ export type StringKebabCase< S extends string, First extends boolean = true, > = S extends `${infer C}${infer Rest}` ? C extends Lowercase ? `${C}${StringKebabCase}` : First extends true ? `${Lowercase}${StringKebabCase}` : `-${Lowercase}${StringKebabCase}` : "" /** * @description Convert a string to camelCase. * * @example * ``` * // Expect: 'helloWorld' * type Example1 = StringCamelCase<'hello-world'> * // Expect: 'helloWorld' * type Example2 = StringCamelCase<'hello--world'> * ``` */ export type StringCamelCase = S extends `${infer First}-${infer Rest}` ? `${Lowercase}${StringCapitalize>}` : S extends `${infer First}_${infer Rest}` ? `${Lowercase}${StringCapitalize>}` : Lowercase /** * @description Convert a string to PascalCase. * * @example * ``` * // Expect: 'HelloWorld' * type Example1 = StringPascalCase<'hello-world'> * // Expect: 'HelloWorld' * type Example2 = StringPascalCase<'HELLO_WORLD'> * ``` */ export type StringPascalCase = StringCapitalize> /** * @description Convert a string to snake_case. * * @example * ``` * // Expect: 'hello_world' * type Example1 = StringSnakeCase<'helloWorld'> * ``` */ export type StringSnakeCase< S extends string, First extends boolean = true, > = S extends `${infer C}${infer Rest}` ? C extends Lowercase ? `${C}${StringSnakeCase}` : First extends true ? `${Lowercase}${StringSnakeCase}` : `_${Lowercase}${StringSnakeCase}` : "" type InternalStringTitleCase< S extends string, ShouldCapitalize extends boolean = true, > = S extends `${infer First}${infer Rest}` ? First extends " " | "-" | "_" ? `${First}${InternalStringTitleCase}` : ShouldCapitalize extends true ? `${Uppercase}${InternalStringTitleCase}` : `${Lowercase}${InternalStringTitleCase}` : "" /** * @description Convert a string to Title Case (capitalize first letter of each word). * * @example * ``` * // Expect: 'Hello World' * type Example1 = StringTitleCase<'hello world'> * // Expect: 'Hello-World-Test' * type Example2 = StringTitleCase<'hello-world-test'> * ``` */ export type StringTitleCase = InternalStringTitleCase /** * @description Convert a string to CONSTANT_CASE. * * @example * ``` * // Expect: 'HELLO_WORLD' * type Example1 = StringConstantCase<'helloWorld'> * // Expect: 'HELLO_WORLD' * type Example2 = StringConstantCase<'hello-world'> * ``` */ export type StringConstantCase< S extends string, First extends boolean = true, > = S extends `${infer C}${infer Rest}` ? C extends "-" | "_" | " " ? `_${StringConstantCase}` : C extends Lowercase ? `${Uppercase}${StringConstantCase}` : First extends true ? `${Uppercase}${StringConstantCase}` : `_${Uppercase}${StringConstantCase}` : "" type InternalStringSwapCase = S extends `${infer First}${infer Rest}` ? First extends Uppercase ? `${Lowercase}${InternalStringSwapCase}` : `${Uppercase}${InternalStringSwapCase}` : "" /** * @description Swap the case of each character in a string. * * @example * ``` * // Expect: 'HELLO world' * type Example1 = StringSwapCase<'hello WORLD'> * ``` */ export type StringSwapCase = InternalStringSwapCase type InternalStringEllipsis< S extends string, Max extends number, Counter extends readonly unknown[] = [], Acc extends string = "", > = Counter["length"] extends Max ? `${Acc}...` : S extends `${infer First}${infer Rest}` ? InternalStringEllipsis : Acc /** * @description Truncate a string with ellipsis if it exceeds maximum length. * * @example * ``` * // Expect: 'hel...' * type Example1 = StringEllipsis<'hello world', 3> * ``` */ export type StringEllipsis = InternalStringEllipsis type InternalStringIndent< S extends string, Spaces extends string, > = S extends `${infer Line}\n${infer Rest}` ? `${Spaces}${Line}\n${InternalStringIndent}` : `${Spaces}${S}` /** * @description Add indentation to each line of a string. * * @example * ``` * // Expect: ' hello\n world' * type Example1 = StringIndent<'hello\nworld', ' '> * ``` */ export type StringIndent = InternalStringIndent< S, Spaces > // ============================================================================ // Conversion // ============================================================================ /** * @description Convert a string literal to a number type (limited to small numbers). * * @example * ``` * // Expect: number * type Example1 = StringToNumber<'123'> * ``` */ export type StringToNumber = S extends `${infer N extends number}` ? N : never /** * @description Convert string 'true' or 'false' to boolean type. * * @example * ``` * // Expect: true * type Example1 = StringToBoolean<'true'> * // Expect: false * type Example2 = StringToBoolean<'false'> * ``` */ export type StringToBoolean = S extends "true" ? true : S extends "false" ? false : never /** * @description Convert a string to an array of characters. * * @example * ``` * // Expect: ['h', 'e', 'l', 'l', 'o'] * type Example1 = StringToTuple<'hello'> * ``` */ export type StringToTuple = StringSplit