UNPKG

@rzl-zone/utils-js

Version:

A modern, lightweight set of JavaScript utility functions for everyday development, crafted to enhance code readability and maintainability.

918 lines (917 loc) 109 kB
/** -------------------------------------------------- * * ***A union type of all valid named CSS colors including `transparent`.*** * -------------------------------------------------- * * This type includes standard color names as defined in the CSS Color Module Specification, * and can be used for validating CSS color inputs in strongly typed UI libraries, themes, or design systems. * * It ensures that only recognized, browser-supported color keywords are accepted. * * @see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/named * @see https://drafts.csswg.org/css-color-4/#named-colors * * @example * const textColor: ColorCssValidBase = "rebeccapurple"; // ✅ valid * const invalidColor: ColorCssValidBase = "superblue"; // ❌ Type error */ type ColorCssValidBase="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"; /** * Returns the second argument if the first argument is `true` (defaults to `true`), otherwise returns the third argument (defaults to `false`) * ```ts * // valid * type Case1 = If<true, 'valid'> * // invalid * type Case2 = If<false, 'valid', 'invalid'> * ``` */ type If<Condition,IfTrue=true,IfFalse=false>=Condition extends true ? IfTrue:IfFalse; /** * Returns a boolean if the passed type is `never` * @example * ```ts * // true * type Case1 = IsNever<never> * // false * type Case2 = IsNever<true> * ``` */ type IsNever<T>=[T] extends [never] ? true:false; /** * Returns the second argument if the first argument is `never` (defaults to `true`), otherwise returns the third argument (defaults to `false`) * @example * ```ts * // 'valid' * type Case1 = IfNever<never, 'valid'> * // 'invalid' * type Case2 = IfNever<never, 'valid', 'invalid'> * ``` */ type IfNever<T,IfTrue=true,IfFalse=false>=If<IsNever<T>,IfTrue,IfFalse>;type NeverifyPropertiesOptions={makeOptional:boolean;}; /** * Turns all properties of an object to type `unknown`. * If `makeOptional` option is `true`, makes all properties optional * @example * ```ts * // {a:never; b:never} * type Result = NeverifyProperties<{a: string; b: string}> * ``` */ type NeverifyProperties<T extends object,Options extends NeverifyPropertiesOptions={makeOptional:false;}>={[K in keyof T]:never;}extends infer Result ? If<Options["makeOptional"],Partial<Result>,Result>:never; /** * Returns the first argument if it is an empty array, otherwise returns `never` * @example * ```ts * // never * type Result = EmptyArray<[1]> * ``` */ type EmptyArray<T extends readonly unknown[]>=T extends readonly [unknown,...unknown[]] ? never:T; /** * Returns the first argument if it is a non empty array, otherwise returns `never` * @example * ```ts * // never * type Result = EmptyArray<[1]> * ``` */ type NonEmptyArray<T extends readonly unknown[]>=If<IsNever<EmptyArray<T>>,T,never>; /** * Returns a boolean whether the passed argument is an empty array * @example * ```ts * // false * type Result - IsEmptyArray<[1]> */ type IsEmptyArray<T extends readonly unknown[]>=If<IsNever<EmptyArray<T>>,false,true>; /** * Returns a boolean whether the passed argument is a non empty array * @example * ```ts * // true * type Result - IsEmptyArray<[1]> */ type IsNonEmptyArray<T extends readonly unknown[]>=If<IsNever<EmptyArray<T>>,true,false>; /** * Returns the second argument if the first argument is an empty array (defaults to `true`), otherwise returns the third argument (defaults to `false`) * @example * ```ts * // string * type Result = IfEmptyArray<[], string, number> * ``` */ type IfEmptyArray<T extends readonly unknown[],IfTrue=true,IfFalse=false>=If<IsEmptyArray<T>,IfTrue,IfFalse>; /** * Returns the second argument if the first argument is a non empty array (defaults to `true`), otherwise returns the third argument (defaults to `false`) * @example * ```ts * // string * type Result = IfEmptyArray<[1], string, number> * ``` */ type IfNonEmptyArray<T extends readonly unknown[],IfTrue=true,IfFalse=false>=If<IsNonEmptyArray<T>,IfTrue,IfFalse>; /** * Accepts a boolean and returns `true` if the passed type is `false`, otherwise returns `true` * @example * ```ts * // false * type Case1 = Not<true> * // true * type Case2 = Not<false> * ``` */ type Not<T extends boolean>=T extends true ? false:true;type PopOptions={includeRemoved:boolean;}; /** * Removes last element from the first array argument. * If the `includeRemoved` option is `true` return removed element with the new array in the format of [rest, removed] * @example * ```ts * // [1, 2] * type Case1 = Pop<[1, 2, 3]> * // [[1, 2], 3] * type Case2 = Pop<[1, 2, 3], {includeRemoved: true}> * ``` */ type Pop<T extends readonly unknown[],Options extends PopOptions={includeRemoved:false;}>=IsEmptyArray<T>extends true ? never:T extends readonly [...infer Rest extends readonly unknown[],infer Removed] ? If<Options["includeRemoved"],[Rest,Removed],Rest>:never; /** * Returns boolean whether the first argument extends the second argument * @example * ```ts * // true * type Case1 = Extends<1, number> * // false * type Case2 = Extends<number, 1> * ``` */ type Extends<T,Base>=[T] extends [Base] ? true:false; /** * Returns boolean whether the first argument doesn't extend the second argument * @example * ```ts * // false * type Case1 = Extends<1, number> * // true * type Case2 = Extends<number, 1> * ``` */ type NotExtends<T,Base>=Not<Extends<T,Base>>; /** * Returns the third argument if the first argument extends the second argument (defaults to `true`), otherwise returns the fourth argument (defaults to `false`) * @example * ```ts * // 'valid' * type Case1 = IfExtends<1, number, 'valid'> * // 'invalid' * type Case2 = IfExtends<1, string, 'valid', 'invalid'> * ``` */ type IfExtends<T,Base,IfTrue=true,IfFalse=false>=If<Extends<T,Base>,IfTrue,IfFalse>; /** * Returns the third argument if the first argument doesn't extend the second argument (defaults to `true`), otherwise returns the fourth argument (defaults to `false`) * @example * ```ts * // 'valid' * type Case1 = IfExtends<1, string, 'valid'> * // 'invalid' * type Case2 = IfExtends<1, number, 'valid', 'invalid'> * ``` */ type IfNotExtends<T,Base,IfTrue=true,IfFalse=false>=If<NotExtends<T,Base>,IfTrue,IfFalse>; /** * Returns boolean whether the every element of first array argument extend the second argument * @example * ```ts * // true * type Case1 = ExtendsArr<[1, 2, 3], number> * // false * type Case1 = ExtendsArr<[1, '2', 3], number> * ``` */ type ExtendsArr<T extends readonly unknown[],Base>=IsEmptyArray<T>extends true ? true:Pop<T,{includeRemoved:true;}>extends readonly [infer Rest extends readonly unknown[],infer Removed] ? Extends<Removed,Base>extends true ? ExtendsArr<Rest,Base>:false:false; /** * Returns result of logical multiplication of two params. * @example * ```ts * // true * type Case1 = And<true, true> * // false * type Case2 = And<false, true> * ``` */ type And<Condition1,Condition2>=IfExtends<Condition1,true,Extends<Condition2,true>>; /** * Returns result of logical multiplication of all elements inside the passed array type * @example * ```ts * // true * type Case1 = And<[true, true, true]> * // false * type Case2 = And<[true, true, false]> * ``` */ type AndArr<Conditions extends readonly unknown[]>=Extends<Conditions[number],true>; /** * Returns a boolean whether the passed argument is literal string * @example * ```ts * // true * type Case1 = IsStringLiteral<'a'> * // false * type Case2 = IsStringLiteral<string> * ``` */ type IsStringLiteral<T extends string>=string extends T ? false:true; /** * Returns the second argument if the first argument is `false` (defaults to `true`), otherwise returns the third argument (defaults to `false`) * @example * ```ts * // valid * type Case1 = IfNot<false, 'valid'> * // invalid * type Case2 = IfNot<false, 'valid', 'invalid'> * ``` */ type IfNot<Condition,IfTrue=true,IfFalse=false>=If<Condition,IfFalse,IfTrue>;type EmptyString<T extends string>="" extends T ? string extends T ? never:T:never;type NonEmptyString<T extends string>=string extends T ? string:If<IsNever<EmptyString<T>>,T,never>;type IsEmptyString<T extends string>=IfNot<IsNever<EmptyString<T>>>;type IsNonEmptyString<T extends string>=IfNot<IsNever<NonEmptyString<T>>>;type IfEmptyString<T extends string,IfTrue=true,IfFalse=false>=IfNot<IsNever<EmptyString<T>>,IfTrue,IfFalse>;type IfNonEmptyString<T extends string,IfTrue=true,IfFalse=false>=IfNot<IsNever<NonEmptyString<T>>,IfTrue,IfFalse>;type _AreAnagrams<Str1 extends string,Str2 extends string>=IsEmptyString<Str1>extends true ? IsEmptyString<Str2>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<Rest1,`${Prev}${Rest2}`>:false:never; /** * Returns a boolean whether two passed string literals are anagrams * @example * ```ts * // true * type Case1 = AreAnagrams<"name", "eman"> * // false * type Case1 = AreAnagrams<"name", "emand"> * ``` */ type AreAnagrams<Str1 extends string,Str2 extends string>=And<IsStringLiteral<Str1>,IsStringLiteral<Str2>>extends true ? _AreAnagrams<Str1,Str2>:false; /** * Returns a boolean whether the passed type is `any` * @example * ```ts * // true * type Result = IsAny<any> * ``` */ type IsAny<T>=0 extends 1 & T ? true:false; /** * Returns the second argument if the first argument is `any` (defaults to `true`), otherwise returns the third argument (defaults to `false`) * @example * ```ts * // string * type Result = IfAny<any, string, number> * ``` */ type IfAny<T,IfTrue=true,IfFalse=false>=If<IsAny<T>,IfTrue,IfFalse>;type AnifyPropertiesOptions={makeOptional:boolean;}; /** * Turns all properties of an object to type `any`. * If `makeOptional` option is `true`, makes all properties optional * @example * ```ts * // {a:any; b:any} * type Result = AnifyProperties<{a: string; b: string}> * ``` */ type AnifyProperties<T extends object,Options extends AnifyPropertiesOptions={makeOptional:false;}>={[K in keyof T]:any;}extends infer Result ? If<Options["makeOptional"],Partial<Result>,Result>:never; /** * Returns the type of the element of the passed array argument * @example * ```ts * // string * type Case1 = ArrayElementType<string[]> * // "a" | "b" * type Case1 = ArrayElementType<readonly ("a" | "b")[]> * ``` */ type ArrayElementType<T extends readonly unknown[]>=T extends Readonly<Array<infer Item>>? Item:never;type LastCharacterOptions={includeRest:boolean;};type _LastCharacter<T extends string,Options extends LastCharacterOptions={includeRest:false;},Previous extends string="">=string extends T ? string:T extends `${infer First}${infer Rest}` ? IsEmptyString<Rest>extends true ? If<Options["includeRest"],[First,Previous],First>:_LastCharacter<Rest,Options,`${Previous}${First}`>:T; /** * Accepts a string argument and returns its first character. * If the `includeRest` options is `true`, returns the first character and the rest of the string in the format of: [last, rest] * @example * ```ts * // 'c' * type Case1 = LastCharacter<'abc'> * // ['c', 'ab'] * type Case2 = LastCharacter<'abc', {includeRest: true}> * ``` */ type LastCharacter<T extends string,Options extends LastCharacterOptions={includeRest:false;}>=_LastCharacter<T,Options>;type EvenDigit="0" | "2" | "4" | "6" | "8";type Integer<T extends number>=`${T}` extends `${string}.${string}` ? never:T;type Float<T extends number>=If<IsNever<Integer<T>>,T,never>;type Negative<T extends number>=`${T}` extends `-${string}` ? T:never;type Positive<T extends number>=If<IsNever<Negative<T>>,T,never>;type PositiveInteger<T extends number>=Positive<Integer<T>>;type NegativeInteger<T extends number>=Negative<Integer<T>>;type PositiveFloat<T extends number>=Positive<Float<T>>;type NegativeFloat<T extends number>=Negative<Float<T>>;type Even<T extends number>=IfNot<IsNever<Integer<T>>,`${T}` extends `${string}${EvenDigit}` ? T:never,never>;type Odd<T extends number>=IfNot<IsNever<Integer<T>>,If<IsNever<Even<T>>,T,never>,never>;type IsInteger<T extends number>=Not<IsNever<Integer<T>>>;type IsFloat<T extends number>=Not<IsNever<Float<T>>>;type IsEven<T extends number>=If<IsInteger<T>,`${T}` extends `${string}${EvenDigit}` ? true:false>;type IsOdd<T extends number>=If<IsInteger<T>,Not<IsEven<T>>>;type IsPositive<T extends number>=Not<IsNever<Positive<T>>>;type IsNegative<T extends number>=Not<IsNever<Negative<T>>>;type IsPositiveInteger<T extends number>=Not<IsNever<PositiveInteger<T>>>;type IsNegativeInteger<T extends number>=Not<IsNever<NegativeInteger<T>>>;type IsPositiveFloat<T extends number>=Not<IsNever<PositiveFloat<T>>>;type IsNegativeFloat<T extends number>=Not<IsNever<NegativeFloat<T>>>;type IfInteger<T extends number,IfTrue=true,IfFalse=false>=If<IsInteger<T>,IfTrue,IfFalse>;type IfFloat<T extends number,IfTrue=true,IfFalse=false>=If<IsFloat<T>,IfTrue,IfFalse>;type IfEven<T extends number,IfTrue=true,IfFalse=false>=If<IsEven<T>,IfTrue,IfFalse>;type IfOdd<T extends number,IfTrue=true,IfFalse=false>=If<IsOdd<T>,IfTrue,IfFalse>;type IfPositive<T extends number,IfTrue=true,IfFalse=false>=If<IsPositive<T>,IfTrue,IfFalse>;type IfNegative<T extends number,IfTrue=true,IfFalse=false>=If<IsNegative<T>,IfTrue,IfFalse>;type IfPositiveInteger<T extends number,IfTrue=true,IfFalse=false>=If<IsPositiveInteger<T>,IfTrue,IfFalse>;type IfNegativeInteger<T extends number,IfTrue=true,IfFalse=false>=If<IsNegativeInteger<T>,IfTrue,IfFalse>;type IfPositiveFloat<T extends number,IfTrue=true,IfFalse=false>=If<IsPositiveFloat<T>,IfTrue,IfFalse>;type IfNegativeFloat<T extends number,IfTrue=true,IfFalse=false>=If<IsNegativeFloat<T>,IfTrue,IfFalse>;type ParseNumber<T extends string | number>=T extends `${infer NumT extends number}` ? NumT:never;type Abs<T extends number>=`${T}` extends `-${infer PositiveT extends number}` ? PositiveT:T;type Negate<T extends number>=ParseNumber<`-${Abs<T>}`>; /** * Returns a boolean whether the first array argument is fixed length tuple * @example * ```ts * // true * type Case1 = IsTuple<[1, 2, 3]> * // false * type Case2 = IsTuple<number[]> * ``` */ type IsTuple<T extends readonly unknown[]>=NotExtends<number,T["length"]>; /** * Type version of `Array.prototype.join()`. Joins the first array argument by the second argument * @example * ```ts * // 'a-p-p-l-e' * type Case1 = Join<["a", "p", "p", "l", "e"], "-"> * // '21212' * type Case2 = Join<["2", "2", "2"], 1> * // 'o' * type Case3 = Join<["o"], "u"> * ``` */ type Join<T extends readonly(string | number)[],Glue extends string | number>=IsTuple<T>extends true ? T extends readonly [infer First extends string | number,...infer Rest extends readonly(string | number)[]] ? IfEmptyArray<Rest,First,`${First}${Glue}${Join<Rest,Glue>}`>:never:never; /** * Transform numbers, booleans, strings, bigints to string. * ```ts * // 'true' * type Result = Stringify<true> * * ``` */ type Stringify<T>=T extends number | boolean | string | bigint ? `${T}`:never;type DecrementMap=[-1,0,1,2,3,4,5,6,7,8];type NegativeCarryMap={"-1":9;};type _Decrement<Number extends string,Result extends string="">=Number extends "" ? ParseNumber<Result>:ParseNumber<LastCharacter<Number>>extends infer LastDigit extends number ? DecrementMap[LastDigit] extends infer Decremented extends number ? Number extends `${infer Rest}${LastDigit}` ? `${Decremented}` extends keyof NegativeCarryMap ? _Decrement<Rest,`${NegativeCarryMap[`${Decremented}`]}${Result}`>:`${Rest}${Decremented}${Result}` extends infer FinalResult extends string ? ParseNumber<FinalResult extends `0${infer FinalResultWithoutLeadingZero extends string}` ? FinalResultWithoutLeadingZero extends "" ? FinalResult:FinalResultWithoutLeadingZero:FinalResult>:never:never:never:never;type _DecrementNegativeOrZero<T extends number>=_Increment<Stringify<T>>extends infer PositiveDecrementResult extends number ? PositiveDecrementResult extends 0 ? PositiveDecrementResult:Negate<PositiveDecrementResult>:never; /** * Accepts an integer and returns the decremented value of it. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // 5 * type Case1 = Decrement<6> * // -7 * type Case2 = Decrement<-6> * ``` */ type Decrement<T extends number>=IsNegative<T>extends true ? _DecrementNegativeOrZero<Abs<T>>:T extends 0 ? _DecrementNegativeOrZero<T>:_Decrement<Stringify<T>>;type IncrementMap=[1,2,3,4,5,6,7,8,9,10];type LastDigitMap={10:0;};type _Increment<Number extends string,Result extends string="">=IsEmptyString<Number>extends true ? ParseNumber<`1${Result}`>:LastCharacter<Number>extends `${infer LastDigit extends number}` ? IncrementMap[LastDigit] extends infer Incremented extends number ? Number extends `${infer Rest}${LastDigit}` ? Incremented extends keyof LastDigitMap ? _Increment<Rest,`${LastDigitMap[Incremented]}${Result}`>:ParseNumber<`${Rest}${Incremented}${Result}`>:never:never:never; /** * Accepts an integer and returns the incremented value of it. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // 2 * type Case1 = Increment<1> * // -9 * type Case1 = Increment<-10> * ``` */ type Increment<T extends number>=IsNegative<T>extends true ? _Decrement<Stringify<Abs<T>>>extends infer NegativeIncrementResult extends number ? NegativeIncrementResult extends 0 ? NegativeIncrementResult:Negate<NegativeIncrementResult>:never:_Increment<Stringify<T>>; /** * Returns a tuple of whole and fraction part of the passed float number * @example * ```ts * [12, 25] * type Case1 = GetFloatNumberParts<12.25> * [12, 25] * type Case2 = GetFloatNumberParts<-12.25> * ``` */ type GetFloatNumberParts<T extends number>=IsFloat<T>extends true ? `${Abs<T>}` extends `${infer Whole extends number}.${infer Fraction extends number}` ? [Whole,Fraction]:never:never; /** * Type version of `Math.ceil()`. Returns ceiled value of the passed number * @example * ```ts * // 2 * type Case1 = Ceil<1.2> * // -1 * type Case2 = Ceil<-1.2> * ``` */ type Ceil<T extends number>=IsFloat<T>extends true ? GetFloatNumberParts<T>extends [infer Whole extends number,unknown] ? IsNegative<T>extends true ? Negate<Whole>:Increment<Whole>:never:T; /** * Returns a boolean whether the passed two arguments are equal * @example * ```ts * // true * type Case1 = IsEqual<string, string> * // false * type Case2 = IsEqual<1, 4> * ``` */ type IsEqual<T,U>=(<F>()=>F extends T ? 1:2)extends<F>()=>F extends U ? 1:2 ? true:false; /** * Returns a boolean whether the passed two arguments are not equal * @example * ```ts * // true * type Case1 = IsNotEqual<1, 4> * // false * type Case2 = IsNotEqual<string, string> * ``` */ type IsNotEqual<T,U>=Not<IsEqual<T,U>>; /** * Accepts two types and returns the third argument if the first two are equal (defaults to `true`), otherwise returns the fourth argument (defaults to `false`) * @example * ```ts * // 'valid' * type Case1 = IfEqual<string, string, 'valid'> * // 'invalid' * type Case1 = IfEqual<1, 4, 'valid', 'invalid'> * ``` */ type IfEqual<T,U,IfTrue=true,IfFalse=false>=If<IsEqual<T,U>,IfTrue,IfFalse>; /** * Accepts two types and returns the third argument if the first two are not equal (defaults to `true`), otherwise returns the fourth argument (defaults to `false`) * @example * ```ts * // 'valid' * type Case1 = IfNotEqual<1, 4, 'valid'> * // 'invalid' * type Case1 = IfNotEqual<string, string, 'valid', 'invalid'> * ``` */ type IfNotEqual<T,U,IfTrue=true,IfFalse=false>=If<IsNotEqual<T,U>,IfTrue,IfFalse>; /** * Accepts a string and removes leading characters specified in the second argument * @example * ```ts * // 'bc' * type Case1 = RemoveLeading<'aaabc', 'a'> * // 'abc' * type Case2 = RemoveLeading<'abc', 'd'> * // '' * type Case3 = RemoveLeading<'aaa', 'a'> * // 'a' * type Case3 = RemoveLeading<'aaa', 'aa'> * ``` */ type RemoveLeading<T extends string,Characters extends string>=T extends `${Characters}${infer Rest extends string}` ? IsEmptyString<Rest>extends true ? Rest:RemoveLeading<Rest,Characters>: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<T extends string>=ParseNumber<RemoveLeading<T,"0">extends infer WithoutLeadingZeros extends string ? IfEmptyString<WithoutLeadingZeros,"0",WithoutLeadingZeros>:never>;type _Sub<Num1 extends string,Num2 extends string,NegativeCarry extends 0 | 1=0,Result extends string="">=IsEmptyString<Num2>extends true ? NegativeCarry extends 0 ? `${Num1}${Result}`:`${Decrement<ParseNumber<Num1>>}${Result}`:LastCharacter<Num1>extends `${infer Num1LastDigit extends keyof SubMap & number}` ? LastCharacter<Num2>extends `${infer Num2LastDigit extends keyof SubMap[Num1LastDigit] & number}` ? `${SubMap[Num1LastDigit][Num2LastDigit]}` extends infer DigitsSub extends keyof SubDecrementMap ?(NegativeCarry extends 1 ? Stringify<SubDecrementMap[DigitsSub]>:DigitsSub)extends infer DigitsSubWithCarry extends string ? Num1 extends `${infer Num1Rest}${Num1LastDigit}` ? Num2 extends `${infer Num2Rest}${Num2LastDigit}` ? DigitsSubWithCarry extends keyof SubNegativeCarryMap ? _Sub<Num1Rest,Num2Rest,1,`${SubNegativeCarryMap[DigitsSubWithCarry]}${Result}`>:_Sub<Num1Rest,Num2Rest,0,`${DigitsSubWithCarry}${Result}`>:never:never:never:never:never:never; /** * Accepts two integers and returns their subtraction. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // 8 * type Case1 = Sub<10, 2> * // -8 * type Case2 = Sub<2, 10> * // 12 * type Case3 = Sub<2, -10> * // -12 * type Case4 = Sub<-2, 10> * ``` */ type Sub<Num1 extends number,Num2 extends number>=IsNegativeInteger<Num1>extends true ? IsNegativeInteger<Num2>extends true ? IsLowerThan<Num1,Num2>extends true ? Negate<_RemoveLeadingZeros<_Sub<Stringify<Abs<Num1>>,Stringify<Abs<Num2>>>>>:_RemoveLeadingZeros<_Sub<Stringify<Abs<Num2>>,Stringify<Abs<Num1>>>>:Sum<Abs<Num1>,Num2>extends infer Result extends number ? Negate<Result>:never:IsNegativeInteger<Num2>extends true ? Sum<Num1,Abs<Num2>>:IsLowerThan<Num1,Num2>extends true ? Negate<_RemoveLeadingZeros<_Sub<Stringify<Num2>,Stringify<Num1>>>>:_RemoveLeadingZeros<_Sub<Stringify<Num1>,Stringify<Num2>>>;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];};type _Sum<Num1 extends string,Num2 extends string,Carry extends 0 | 1=0,Result extends string="">=IsEmptyString<Num1>extends true ? Carry extends 0 ? ParseNumber<`${Num2}${Result}`>:_Increment<Num2,Result>:IsEmptyString<Num2>extends true ? Carry extends 0 ? ParseNumber<`${Num1}${Result}`>:_Increment<Num1,Result>:LastCharacter<Num1>extends `${infer Num1LastDigit extends keyof SumMap & number}` ? LastCharacter<Num2>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<Num1Rest,Num2Rest,1,`${SumLastDigitMap[DigitsSumWithCarry]}${Result}`>:_Sum<Num1Rest,Num2Rest,0,`${DigitsSumWithCarry}${Result}`>:never:never:never:never:never:never; /** * Accepts two integers and returns their sum. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // 13 * type Case1 = Sum<4, 9> * // 5 * type Case2 = Sum<-4, 9> * // -5 * type Case3 = Sum<4, -9> * // -13 * type Case4 = Sum<-4, -9> * ``` */ type Sum<Num1 extends number,Num2 extends number>=IsNegativeInteger<Num1>extends true ? IsNegativeInteger<Num2>extends true ? Negate<_Sum<Stringify<Abs<Num1>>,Stringify<Abs<Num2>>>>:Sub<Num2,Abs<Num1>>:IsNegativeInteger<Num2>extends true ? Sub<Num1,Abs<Num2>>:_Sum<Stringify<Num1>,Stringify<Num2>>;type _SumArr<T extends readonly number[],CurrentSum extends number=0>=IsEmptyArray<T>extends true ? CurrentSum:Pop<T,{includeRemoved:true;}>extends infer PopResult ? IsNever<PopResult>extends true ? CurrentSum:PopResult extends [infer Rest extends number[],infer Num1 extends number] ? _SumArr<Rest,Sum<CurrentSum,Num1>>:never:CurrentSum; /** * Accepts an array of integers and returns the sum of its elements. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // 10 * type Case1 = SumArr<[1, 2, 3, 4]> * // 2 * type Case2 = SumArr<[1, 2, 3, -4]> * ``` */ type SumArr<T extends readonly number[]>=IsTuple<T>extends true ? _SumArr<T>:never;type _StringLength<S extends string,Parts extends [string[],string[],string[],string[]]=[[],[],[],[]]>=S extends "" ? Sum<Sum<Parts[0]["length"],Parts[1]["length"]>,Sum<Parts[2]["length"],Parts[3]["length"]>>: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<Rest4,[[...Parts[0],C1],[...Parts[1],C2],[...Parts[2],C3],[...Parts[3],C4]]>:_StringLength<Rest3,[[...Parts[0],C1],[...Parts[1],C2],[...Parts[2],C3],Parts[3]]>:_StringLength<Rest2,[[...Parts[0],C1],[...Parts[1],C2],Parts[2],Parts[3]]>:_StringLength<Rest1,[[...Parts[0],C1],Parts[1],Parts[2],Parts[3]]>:_StringLength<S,Parts>; /** * Returns the length of the passed string. Range of string length `[0, 3968]` * @example * ```ts * // 0 * type Case1 = StringLength<''> * // 3 * type Case2 = StringLength<'xxx'> * ``` */ type StringLength<S extends string>=_StringLength<S>; /** * Accepts two strings, returns the third argument (defaults to `never`) if the first string is shorter, otherwise returns the fourth argument (defaults to `never`) if the second argument is shorter, if strings have the same length returns the fifth argument (defaults to `never`) * @example * ```ts * // 'first shorter' * type Case1 = CompareStringLength<'a', 'ab', 'first shorter'> * // 'first longer' * type Case2 = CompareStringLength<'abc', 'ab', 'first shorter', 'first longer'> * // 'equal' * type Case3 = CompareStringLength<'ab', 'ab', 'first shorter', 'first longer', 'equal'> * ``` */ type CompareStringLength<Str1 extends string,Str2 extends string,IfStr1Shorter=never,IfStr2Shorter=never,IfEqual=never>=IsEmptyString<Str1>extends true ? IsEmptyString<Str2>extends true ? IfEqual:IfStr1Shorter:IsEmptyString<Str2>extends true ? IfStr2Shorter:Str1 extends `${string}${infer Str1Rest extends string}` ? Str2 extends `${string}${infer Str2Rest extends string}` ? CompareStringLength<Str1Rest,Str2Rest,IfStr1Shorter,IfStr2Shorter,IfEqual>:never:never; /** * Accepts two strings, returns a boolean whether the first string is shorter * @example * ```ts * // true * type Case1 = IsShorterString<'a', 'ab'> * // false * type Case2 = IsShorterString<'abc', 'ab'> * ``` */ type IsShorterString<Str1 extends string,Str2 extends string>=CompareStringLength<Str1,Str2,true,false,false>; /** * Accepts two strings, returns a boolean whether the first string is longer * @example * ```ts * // true * type Case1 = IsLongerString<'ab', 'a'> * // false * type Case2 = IsLongerString<'a', 'ab'> * ``` */ type IsLongerString<Str1 extends string,Str2 extends string>=CompareStringLength<Str1,Str2,false,true,false>; /** * Accepts two strings, returns a boolean whether strings have the same length * @example * ```ts * // true * type Case1 = IsSameLengthString<'ab', 'ab'> * // false * type Case2 = IsSameLengthString<'ab', 'abc'> * ``` */ type IsSameLengthString<Str1 extends string,Str2 extends string>=CompareStringLength<Str1,Str2,false,false,true>; /** * Returns number of digits of the passed number * @example * ```ts * // 3 * type Case1 = NumberLength<100> * // 15 * type Case2 = NumberLength<100000000000000> * ``` */ type NumberLength<T extends number>=StringLength<Stringify<T>>; /** * Accepts two numbers, returns the third argument (defaults to `never`) if the first number is shorter, otherwise returns the fourth argument (defaults to `never`) if the second argument is shorter, if numbers have the same length returns the fifth argument (defaults to `never`) * @example * ```ts * // 'first shorter' * type Case1 = CompareNumberLength<1, 12, 'first shorter'> * // 'first longer' * type Case2 = CompareNumberLength<123, 12, 'first shorter', 'first longer'> * // 'equal' * type Case3 = CompareNumberLength<12, 12, 'first shorter', 'first longer', 'equal'> * ``` */ type CompareNumberLength<Num1 extends number,Num2 extends number,IfNum1Shorter=never,IfNum2Shorter=never,IfEqual=never>=CompareStringLength<Stringify<Num1>,Stringify<Num2>,IfNum1Shorter,IfNum2Shorter,IfEqual>; /** * Accepts two numbers, returns a boolean whether the first number is shorter * @example * ```ts * // true * type Case1 = IsShorterNumber<1, 10> * // false * type Case2 = IsShorterNumber<100, 10> * ``` */ type IsShorterNumber<Num1 extends number,Num2 extends number>=CompareNumberLength<Num1,Num2,true,false,false>; /** * Accepts two numbers, returns a boolean whether the first number is longer * @example * ```ts * // true * type Case1 = IsLongerNumber<10, 1> * // false * type Case2 = IsLongerNumber<10, 100> * ``` */ type IsLongerNumber<Num1 extends number,Num2 extends number>=CompareNumberLength<Num1,Num2,false,true,false>; /** * Accepts two numbers, returns a boolean whether numbers have the same length * @example * ```ts * // true * type Case1 = IsSameLengthNumber<10, 10> * // false * type Case2 = IsSameLengthNumber<10, 100> * ``` */ type IsSameLengthNumber<Num1 extends number,Num2 extends number>=CompareNumberLength<Num1,Num2,false,false,true>;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 string,Num2 extends string>=Num1 extends `${infer Num1Character extends keyof LowerThanMap}${infer Num1Rest extends string}` ? Num2 extends `${infer Num2Character extends string}${infer Num2Rest extends string}` ? IsEqual<Num1Character,Num2Character>extends true ? _IsLowerThan<Num1Rest,Num2Rest>:Num2Character extends LowerThanMap[Num1Character][number] ? true:false:true:false; /** * Returns a boolean whether the first passed integer is lower than the second integer. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // true * type Case1 = IsLowerThan<1, 10> * // false * type Case2 = IsLowerThan<1, -10> * ``` */ type IsLowerThan<Num1 extends number,Num2 extends number>=IsEqual<Num1,Num2>extends true ? false:IsNegative<Num1>extends true ? IsNegative<Num2>extends false ? true:CompareNumberLength<Num1,Num2,false,true,Not<_IsLowerThan<Stringify<Abs<Num1>>,Stringify<Abs<Num2>>>>>:IsNegative<Num2>extends true ? false:CompareNumberLength<Num1,Num2,true,false,_IsLowerThan<Stringify<Abs<Num1>>,Stringify<Abs<Num2>>>>; /** * Returns a boolean whether the first passed integer is lower than the second integer. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // 'valid' * type Case1 = IfLowerThan<1, 10, 'valid'> * // 'invalid' * type Case2 = IfLowerThan<1, -10, 'valid', 'invalid'> * ``` */ type IfLowerThan<Num1 extends number,Num2 extends number,IfTrue=true,IfFalse=false>=If<IsLowerThan<Num1,Num2>,IfTrue,IfFalse>;type IsLowerOrEqual<Num1 extends number,Num2 extends number>=IsEqual<Num1,Num2>extends true ? true:IsLowerThan<Num1,Num2>; /** * Returns a boolean whether the first passed integer is greater than the second integer. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // true * type Case1 = IsGreaterThan<10, 1> * // false * type Case2 = IsGreaterThan<-10, 1> * ``` */ type IsGreaterThan<Num1 extends number,Num2 extends number>=IsLowerThan<Num2,Num1>; /** * Returns the third argument if the first argument (integer) is greater than the second argument (integer) (defaults to `true`), otherwise returns the fourth argument (defaults to `false`). Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * 'valid' * type Case1 = IfGreaterThan<10, 1, 'valid'> * // 'invalid' * type Case2 = IfGreaterThan<-10, 1, 'valid', 'invalid'> * ``` */ type IfGreaterThan<Num1 extends number,Num2 extends number,IfTrue=true,IfFalse=false>=IfLowerThan<Num2,Num1,IfTrue,IfFalse>; /** * Returns a boolean whether the first passed integer is greater than the second integer or equal. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // true * type Case1 = IsGreaterThan<10, 1> * // false * type Case2 = IsGreaterThan<-10, 1> * // true * type Case3 = IsGreaterThan<10, 10> * ``` */ type IsGreaterOrEqual<Num1 extends number,Num2 extends number>=IsEqual<Num1,Num2>extends true ? true:IsGreaterThan<Num1,Num2>; /** * Returns the third argument if the first argument (integer) is greater 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]` * @example * ```ts * 'valid' * type Case1 = IfGreaterThan<10, 1, 'valid'> * // 'invalid' * type Case2 = IfGreaterThan<-10, 1, 'valid', 'invalid'> * ``` */ type IfGreaterOrEqual<Num1 extends number,Num2 extends number,IfTrue=true,IfFalse=false>=If<IsEqual<Num1,Num2>extends true ? true:IsGreaterThan<Num1,Num2>,IfTrue,IfFalse>;type IsBetweenOptions={minIncluded?:boolean;maxIncluded?:boolean;}; /** * 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. * `minIncluded`, `maxIncluded` options show whether to include the lower and the higher borders respectively. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]` * @example * ```ts * // true * type Case1 = IsBetween<1, 1, 10> * // false * type Case2 = IsBetween<1, 1, 10, {minIncluded: false}> * // false * type Case3 = IsBetween<10, 1, 10, {maxIncluded: false}> * ``` */ type IsBetween<Num extends number,Min extends number,Max extends number,Options extends IsBetweenOptions={minIncluded:true;maxIncluded:true;}>=IsEqual<Num,Min>extends true ? Options["minIncluded"]:IsEqual<Num,Max>extends true ? Options["maxIncluded"]:And<IsGreaterThan<Num,Min>,IsLowerThan<Num,Max>>; /** * Type version of `String.prototype.split()`. Splits the first string argument by the second string argument * @example * ```ts * // ['a', 'b', 'c'] * type Case1 = Split<'abc', ''> * // ['a', 'b', 'c'] * type Case2 = Split<'a,b,c', ','> * ``` */ type Split<Str extends string,Del extends string | number>=string extends Str ? string[]:"" extends Str ? []:Str extends `${infer T}${Del}${infer U}` ? [T,...Split<U,Del>]:[Str];type _IsValidRGBParameter<T extends number>=IsInteger<T>extends true ? IsBetween<T,0,255>:false;type RGBOptions={separator:string;};type DefaultRGBOptions={separator:",";}; /** * Returns the first string argument if it is a valid RGB color, otherwise returns `never`. * The second argument is an object type with `separator: string` property, which shows the separator between color parameters (defaults to `', '`) * @example * ```ts * // rgb(23, 242, 0) * type Case1 = RGB<'rgb(23, 242, 0)'> * // never * type Case2 = RGB<'rgb(324, 123, 3)'> * // rgb(23,242,0) * type Case3 = RGB<'rgb(23,242,0)', { separator: ',' }> * ``` */ type RGB<T extends string,Options extends RGBOptions=DefaultRGBOptions>=T extends `rgb(${infer R extends number}${Options["separator"]}${infer G extends number}${Options["separator"]}${infer B extends number})` ? AndArr<[_IsValidRGBParameter<R>,_IsValidRGBParameter<G>,_IsValidRGBParameter<B>]>extends true ? T:never:never; /** * Returns a boolean whether the first string argument is a valid RGB color. * The second argument is an object type with `separator: string` property, which shows the separator between color parameters (defaults to `', '`) * @example * ```ts * // true * type Case1 = IsRGB<'rgb(23, 242, 0)'> * // false * type Case2 = IsRGB<'rgb(324, 123, 3)'> * // true * type Case3 = IsRGB<'rgb(23,242,0)', { separator: ',' }> * ``` */ type IsRGB<T extends string,Options extends RGBOptions=DefaultRGBOptions>=Not<IsNever<RGB<T,Options>>>; /** * Returns the third argument if the first argument is valid RGB color (defaults to `true`), otherwise returns the fourth argument (defaults to `false`) * The second argument is an object type with `separator: string` property, which shows the separator between color parameters (defaults to `', '`) * @example * ```ts * // 'true' * type Case1 = IfRGB<'rgb(23, 242, 0)', 'true'> * // 'invalid' * type Case2 = IfRGB<'rgb(324, 123, 3)', 'valid', 'invalid'> * // true * type Case3 = IfRGB<'rgb(23,242,0)', { separator: ',' }> * ``` */ type IfRGB<T extends string,Options extends RGBOptions=DefaultRGBOptions,IfTrue=true,IfFalse=false>=If<IsRGB<T,Options>,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; /** * Returns the first string argument if it is a valid HEX color, otherwise returns `never` * @example * // '#000' * type Case1 = HEX<'#000'> * // never * type Case2 = HEX<'#g00'> * // '#0000' * type Case3 = HEX<'#0000'> * // never * type Case4 = HEX<'#00000'> * // '#000000' * type Case5 = HEX<'#000000'> * // '#00000000' * type Case6 = HEX<'#00000000'> */ type HEX<T extends string>=(Uppercase<T>extends `#${infer HEXWithoutHashTag extends string}` ? StringLength<HEXWithoutHashTag>extends _AllowedHEXLength ? ExtendsArr<Split<HEXWithoutHashTag,"">,_ValidHEXCharacters[number]>:false:false)extends true ? T:never; /** * Returns a boolean whether the first string argument is a valid HEX color. * @example * ```ts * // true * type Case1 = IsHEX<'#000'> * // false * type Case2 = IsHEX<'#g00'> * ``` */ type IsHEX<T extends string>=Not<IsNever<HEX<T>>>; /** * Returns the second argument if the first argument is valid HEX color (defaults to `true`), otherwise returns the third argument (defaults to `false`) * @example * ```ts * // true * type Case1 = IfHEX<'#000'> * // false * type Case2 = IfHEX<'#g00'> * // 'valid' * type Case3 = IfHEX<'#0000', 'valid'> * // 'invalid' * type Case4 = IfHEX<'#00000', 'valid', 'invalid'> * ``` */ type IfHEX<T extends string,IfTrue=true,IfFalse=false>=If<IsHEX<T>,IfTrue,IfFalse>;type HSLOptions={separator:string;};type DefaultHSLOptions={separator:",";}; /** * Returns the first string argument if it is a valid HSL color, otherwise returns `never`. * The second argument is an object type with `separator: string` property, which shows the separator between color parameters (defaults to `', '`) * @example * ```ts * // hsl(100, 34%, 56%) * type Case1 = HSL<'hsl(100, 34%, 56%)'> * // never * type Case2 = HSL<'hsl(100, 200%, 3)'> * // hsl(100,34%,56%) * type Case3 = HSL<'hsl(100,34%,56%)', { separator: ',' }> * ``` */ type HSL<T extends string,Options extends HSLOptions=DefaultHSLOptions>=(T extends `hsl(${infer H extends number}${Options["separator"]}${infer S extends number}%${Options["separator"]}${infer L extends number}%)` ? AndArr<[IsInteger<H>,IsInteger<S>,IsInteger<L>]>extends true ? AndArr<[IsBetween<S,0,100>,IsBetween<L,0,100>]>:false:false)extends true ? T:never; /** * Returns a boolean whether the first string argument is a valid HSL color. * The second argument is an object type with `separator: string` property, which shows the separator between color parameters (defaults to `', '`) * @example * ```ts * // true * type Case1 = IsHSL<'hsl(100, 34%, 56%)'> * // false * type Case2 = IsHSL<'hsl(101, 200%, 3)'> * // true * type Case3 = IsHSL<'hsl(100,34%,56%)', { separator: ',' }> * ``` */ type IsHSL<T extends string,Options extends HSLOptions=DefaultHSLOptions>=Not<IsNever<HSL<T,Options>>>; /** * Returns the third argument if the first argument is valid HSL color (defaults to `true`), otherwise returns the fourth argument (defaults to `false`) * The second argument is an object type with `separator: string` property, which shows the separator between color parameters (defaults to `', '`) * @example * ```ts * // 'true' * type Case1 = IfHSL<'hsl(100, 34%, 56%)', 'true'> * // 'invalid' * type Case2 = IfHSL<'hsl(101, 200%, 3)', 'valid', 'invalid'> * // true * type Case3 = IfHSL<'hsl(100,34%,56%)', { separator: ',' }> * ``` */ type IfHSL<T extends string,Options extends HSLOptions=DefaultHSLOptions,IfTrue=true,IfFalse=false>=If<IsHSL<T,Options>,IfTrue,IfFalse>;type ColorOptions={rgbOptions?:RGBOptions;hslOptions?:HSLOptions;};type DefaultColorOptions={rgbOptions:DefaultRGBOptions;hslOptions:DefaultHSLOptions;}; /** * Returns the first string argument if it is a valid RGB or HEX or HSL color, otherwise returns `never`. * The second argument is an object type with `rgbOptions: RGBOptions` and `hslOptions: hslOptions` properties, which can accept the separator between color parameters (defaults to `', '`) * @example * ```ts * // rgb(23, 242, 0) * type Case1 = Color<'rgb(23, 242, 0)'> * // never * type Case2 = Color<'rgb(324, 123, 3)'> * // '#000000' * type Case3 = HEX<'#000000'> * // 'hsl(100,34%,56%)' * type Case4 = Color<'hsl(100,34%,56%)', { hslOptions: { separator: ',' } }> * ``` */ type Color<T extends string,Options extends ColorOptions=DefaultColorOptions>=RGB<T,Options["rgbOptions"]>| HEX<T>| HSL<T,Options["hslOptions"]>; /** * Returns a boolean whether the first string argument is a valid RGB or HEX or HSL color. * The second argument is an object type with `rgbOptions: RGBOptions` and `hslOptions: hslOptions` properties, which can accept the separator between color parameters (defaults to `', '`) * @example * ```ts * // true * type Case1 = Color<'rgb(23, 242, 0)'> * // false * type Case2 = Color<'rgb(324, 123, 3)'> * // true * type Case3 = HEX<'#000000'> * // true * type Case4 = Color<'hsl(100,34%,56%)', { hslOptions: { separator: ',' } }> * ``` */ type IsColor<T extends string,Options extends ColorOptions=DefaultColorOptions>=Not<IsNever<Color<T,Options>>>; /** * Returns the third argument if the first argument is valid RGB or HEX or HSL color (defaults to `true`), otherwise returns the fourth argument (defaults to `false`) * The second argument is an object type with `rgbOptions: RGBOptions` and `hslOptions: hslOptions` properties, which can accept the separator between color parameters (defaults to `', '`) * @example * ```ts * // 'valid' * type Case1 = Color<'rgb(23, 242, 0)', 'valid'> * // 'invalid' * type Case2 = Color<'rgb(324, 123, 3)', 'valid', 'invalid'> * // true * type Case3 = Color<'#000000'> * ``` */ type IfColor<T extends string,Options extends ColorOptions=DefaultColorOptions,IfTrue=true,IfFalse=false>=If<IsColor<T,Options>,IfTrue,IfFalse>; /** * Type version of `Array.prototype.concat()`. Concatenates two arrays into one. * @example * ```ts * // [number, number, string, string] * type Result = Concat<[number, number], [string, string]> * ``` */ type Concat<T extends readonly unknown[],U>=[...T,...(U extends readonly unknown[] ? U:[U])]; /** * Accepts an integer argument and returns a tuple of its digits * @example * ```ts * // [1] * type Case1 = DigitsTuple<1> * // [1, 2, 3] * type Case2 = DigitsTuple<123> * // [1, 2, 3] * type Case3 = DigitsTuple<-123> * ``` */ type DigitsTuple<T extends number>=number extends T ? number[]:Split<Stringify<Abs<T>>,"">extends infer Result ?{[K in keyof Result]:Result[K] extends string ? ParseNumber<Result[K]>:Result[K];}:never; /** * Pushes the second argument to the first array argument * @example * ```ts * // [1, 2, 3, 4, 5] * type Case1 = Push<[1, 2, 3, 4], 5> * ``` */ type Push<T extends readonly unknown[],U extends unknown>=[...T,U];type _Repeat<T extends string,Count extends number,Result extends string="",Iteration extends unknown[]=[]>=Iteration["length"] extends Count ? Result:_Repeat<T,Count,`${T}${Result}`,Push<Iteration,unknown>>; /** * Repeats the first argument number of times specified in the second argument. Range `[0,999]` * @example * ```ts * // 'x' * type Case1 = Repeat<'x', 1> * // 'xxxxx' * type Case2 = Repeat<'x', 5> * ``` */ type Repeat<T extends string,Count extends number>=_Repeat<T,Count>; /** * Returns the first argument if it extends the second argument, returns the third argument otherwise * @example * ```ts * // 1 * type Case1 = ReturnItselfIfExtends<1, number, 2> * // 2 * type Case2 = ReturnItselfIfExtends<'1', number, 2> * ``` */ type ReturnItselfIfExtends<T,Base,Else>=T extends Base ? T:Else; /** * Returns the first argument if it doesn't extend the second argument, returns the third argument otherwise * @example * ```ts * // '1' * type Case1 = ReturnItselfIfNotExtends<'1', number, 2> * // 2 * type Case2 = ReturnItselfIfNotExtends<1, number, 2> * ``` */ type ReturnItselfIfNotExtends<T,Base,Else>=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 _MultSingle<Num1 extends string,DigitOfNum2 extends keyof MultiplicationMap,Carry extends number=0,Result extends string="">=IsEmptyString<Num1>extends true ? ReturnItselfIfNotExtends<RemoveLeading<`${Carry}${Result}`,"0">,"","0">:IsEqual<Num1,0>extends true ? "0":IsEqual<DigitOfNum2,0>extends true ? "0":LastCharacter<Num1,{includeRest:true;}>extends [infer Num1LastCharacter extends string,infer Num1Rest extends string] ? Stringify<Sum<MultiplicationMap[DigitOfNum2][ParseNumber<Num1LastCharacter>& keyof MultiplicationMap[DigitOfNum2]],Carry>>extends infer Multiplied extends string ? LastCharacter<Multiplied,{includeRest:true;}>extends [infer MultipliedLastDigit extends string,infer MultipliedRest extends string] ? _MultSingle<Num1Rest,DigitOfNum2,If<IsNever<ParseNumber<MultipliedRest>>,0,ParseNumber<MultipliedRest>>,`${MultipliedLastDigit}${Result}`>:never:never:never;type _Mult<Num1 extends string,Num2 extends string,Result extends string="",Iteration extends unknown[]=[]>=IsEmptyString<Num2>extends true ? Result:LastCharacter<Num2,{includeRest:true;}>extends [infer Num2LastCharacter extends string,infer Num2Rest extends string] ? ParseNumber<Num2LastCharacter>extends infer Num2Digit extends keyof MultiplicationMap ? _Mult<Num1,Num2Rest,Stringify<_Sum<Result,ReturnItselfIfNotExtends<Remov