/**
 * 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>;

/**
 * Returns a boolean whether the first passed integer is lower or equal to the second integer. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // true
 * type Case1 = IsLowerOrEqual<1, 10>
 * // false
 * type Case2 = IsLowerOrEqual<1, -10>
 * ```
 */
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<
              RemoveLeading<
                `${_MultSingle<Num1, Num2Digit>}${Repeat<
                  "0",
                  Iteration["length"]
                >}`,
                "0"
              >,
              "",
              "0"
            >
          >
        >,
        Push<Iteration, unknown>
      >
    : never
  : Result;

/**
 * Accepts tow integers and returns their multiplication. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // 0
 * type Case1 = Mult<10, 0>
 * // 24
 * type Case2 = Mult<4, 6>
 * // -24
 * type Case3 = Mult<-4, 6>
 * // 24
 * type Case4 = Mult<-4, -6>
 * ```
 */
type Mult<Num1 extends number, Num2 extends number> = IsEqual<
  Num1,
  0
> extends true
  ? 0
  : IsEqual<Num2, 0> extends true
  ? 0
  : ParseNumber<
      _Mult<Stringify<Abs<Num1>>, Stringify<Abs<Num2>>>
    > extends infer Result extends number
  ? IfNegative<
      Num1,
      IfNegative<Num2, Result, Negate<Result>>,
      IfNegative<Num2, Negate<Result>, Result>
    >
  : never;

/**
 * Returns result of logical addition of two params.
 * @example
 * ```ts
 * // true
 * type Case1 = Or<true, true>
 * // true
 * type Case2 = Or<false, true>
 * ```
 */
type Or<Condition1, Condition2> = IfExtends<
  Condition1,
  true,
  true,
  IfExtends<Condition2, true>
>;

/**
 * Returns result of logical addition of all elements inside the passed array type
 * @example
 * ```ts
 * // true
 * type Case1 = Or<[true, true, true]>
 * // true
 * type Case2 = Or<[true, true, false]>
 * ```
 */
type OrArr<Conditions extends readonly unknown[]> =
  true extends Conditions[number] ? true : false;

type _FindQuotient<
  Dividend extends number,
  Divisor extends number,
  CurrentQuotient extends number
> = Mult<Divisor, CurrentQuotient> extends infer Product extends number
  ? IsEqual<Dividend, Product> extends true
    ? CurrentQuotient
    : IsLowerThan<Dividend, Product> extends true
    ? _FindQuotient<Dividend, Divisor, Decrement<CurrentQuotient>>
    : CurrentQuotient
  : never;

type _Div<
  Dividend extends string,
  Divisor extends number,
  Result extends string = "",
  CurrentDividend extends string = "",
  IterationsWithoutDivision extends number = 0,
  HadFirstDivision extends boolean = false
> = Or<
  IsEmptyString<CurrentDividend>,
  IsLowerThan<ParseNumber<CurrentDividend>, Divisor>
> extends true
  ? IsEmptyString<Dividend> extends true
    ? ParseNumber<
        If<
          And<HadFirstDivision, IsNotEqual<IterationsWithoutDivision, 0>>,
          `${Result}0`,
          Result
        >
      >
    : Dividend extends `${infer FirstDigit extends string}${infer Rest extends string}`
    ? _Div<
        Rest,
        Divisor,
        If<
          And<HadFirstDivision, IsNotEqual<IterationsWithoutDivision, 0>>,
          `${Result}0`,
          Result
        >,
        IfEqual<
          CurrentDividend,
          "0",
          FirstDigit,
          `${CurrentDividend}${FirstDigit}`
        >,
        Increment<IterationsWithoutDivision>,
        HadFirstDivision
      >
    : never
  : _FindQuotient<
      ParseNumber<CurrentDividend>,
      Divisor,
      10
    > extends infer Quotient extends number
  ? IsNever<Quotient> extends true
    ? ParseNumber<Result>
    : Sub<
        ParseNumber<CurrentDividend>,
        Mult<Quotient, Divisor>
      > extends infer Remainder extends number
    ? _Div<
        Dividend,
        Divisor,
        `${Result}${Quotient}`,
        IfGreaterThan<Remainder, 0, `${Remainder}`, "">,
        0,
        true
      >
    : never
  : never;

/**
 * Returns integer division of two numbers. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // 5
 * type Case1 = Div<10, 2>
 * // 2
 * type Case2 = Div<7, 3>
 * ```
 */
type Div<Dividend extends number, Divisor extends number> = IsEqual<
  Divisor,
  0
> extends true
  ? never
  : IsEqual<Dividend, 0> extends true
  ? 0
  : IsEqual<Dividend, Divisor> extends true
  ? 1
  : IsLowerThan<Abs<Dividend>, Abs<Divisor>> extends true
  ? 0
  : _Div<
      Stringify<Abs<Dividend>>,
      Abs<Divisor>
    > extends infer Quotient extends number
  ? If<
      Or<
        And<IsNegative<Dividend>, IsNegative<Divisor>>,
        And<IsPositive<Dividend>, IsPositive<Divisor>>
      >,
      Quotient,
      Negate<Quotient>
    >
  : never;

/**
 * Returns result of concatenation of two string literals with '.' if the second literal is not empty. otherwise returns the first string literal.
 * @example
 * ```ts
 * // 'foo.bar'
 * type Result = Dot<'foo', 'bar'>
 * ```
 */
type Dot<T extends string, U extends string> = "" extends U
  ? T
  : `${T}.${U}`;

/**
 * Returns a boolean whether the first string argument ends with the second one
 * @example
 * ```ts
 * // true
 * type Result = EndsWith<'Foobar', 'bar'>
 * ```
 */
type EndsWith<
  T extends string,
  Characters extends string
> = T extends `${string}${Characters}` ? true : false;

type _Factorial<
  T extends number,
  CurrentNum extends number = 1,
  CurrentProduct extends number = 1
> = IsEqual<T, CurrentNum> extends true
  ? Mult<CurrentProduct, CurrentNum>
  : _Factorial<T, Increment<CurrentNum>, Mult<CurrentProduct, CurrentNum>>;

/**
 * Accepts an integer argument and returns it mathematical factorial. Range: [0, 21]
 * @example
 * // 0
 * type Case1 = Factorial<0>
 * // 720
 * type Case1 = Factorial<6>
 */
type Factorial<T extends number> = number extends T
  ? never
  : IsNegative<T> extends true
  ? never
  : IsEqual<T, 0> extends true
  ? 1
  : _Factorial<T>;

/**
 * Returns the fibonacci sequence number under the passed integer index. Range: `[0, 78]`
 * @example
 * ```ts
 * // 3
 * type Case1 = Fibonacci<4>
 * // 102334155
 * type Case2 = Fibonacci<40>
 * ```
 */
type Fibonacci<T extends number> = IsNegative<T> extends true
  ? never
  : IsLowerThan<T, 2> extends true
  ? T
  : Fibonacci<Decrement<T>> extends infer NMinusOne extends number
  ? Fibonacci<Sub<T, 2>> extends infer NMinusTwo extends number
    ? Sum<NMinusOne, NMinusTwo>
    : never
  : never;

type FirstCharacterOptions = {
  includeRest: boolean;
};

/**
 * 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: [first, rest]
 * @example
 * ```ts
 * // 'a'
 * type Case1 = FirstCharacter<'abc'>
 * // ['a', 'bc']
 * type Case2 = FirstCharacter<'abc', {includeRest: true}>
 * ```
 */
type FirstCharacter<
  T extends string,
  Options extends FirstCharacterOptions = { includeRest: false }
> = T extends `${infer First extends string}${infer Rest extends string}`
  ? If<Options["includeRest"], [First, Rest], First>
  : never;

/**
 * Returns the first digit of the number argument
 * @example
 * ```ts
 * // 1
 * type Case1 = FirstDigit<123>
 * // -1
 * type Case2 = FirstDigit<-123>
 * ```
 */
type FirstDigit<T extends number> = DigitsTuple<T> extends readonly [
  infer First extends number,
  ...unknown[]
]
  ? First
  : never;

/**
 * Type version of `Math.floor()`. Returns floored value of the passed number
 * @example
 * ```ts
 * // 1
 * type Case1 = Ceil<1.9>
 * // -2
 * type Case2 = Ceil<-1.2>
 * ```
 */
type Floor<T extends number> = IsFloat<T> extends true
  ? GetFloatNumberParts<T> extends [infer Whole extends number, unknown]
    ? IsNegative<T> extends true
      ? Negate<Increment<Whole>>
      : Whole
    : never
  : T;

type ShiftOptions = {
  includeRemoved: boolean;
};

/**
 * Removes the first 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
 * // [2, 3]
 * type Case1 = Shift<[1, 2, 3]>
 * // [[2, 3], 1]
 * type Case2 = Shift<[1, 2, 3], {includeRemoved: true}>
 * ```
 */
type Shift<
  T extends readonly unknown[],
  Options extends ShiftOptions = { includeRemoved: false }
> = T extends readonly [infer Removed, ...infer Rest extends readonly unknown[]]
  ? If<Options["includeRemoved"], [Rest, Removed], Rest>
  : never;

/**
 * Returns a boolean whether the second argument is in the first array argument
 * @example
 * ```ts
 * // true
 * type Case1 = Includes<[1, 2, 3], 1>
 * // false
 * type Case1 = Includes<[1, 2, 3], 4>
 * ```
 */
type Includes<
  T extends readonly unknown[],
  Pivot
> = IsEmptyArray<T> extends true
  ? false
  : Shift<T, { includeRemoved: true }> extends [
      infer Rest extends readonly unknown[],
      infer Removed
    ]
  ? IfEqual<Pivot, Removed, true, Includes<Rest, Pivot>>
  : false;

type _IndexOfArray<
  T extends readonly unknown[],
  Pivot,
  Index extends number = 0
> = T extends readonly [infer First, ...infer Rest extends unknown[]]
  ? IsEqual<First, Pivot> extends true
    ? Index
    : _IndexOfArray<Rest, Pivot, Increment<Index>>
  : -1;

type _IndexOfString<
  T extends string,
  Pivot,
  Index extends number = 0
> = T extends `${infer First}${infer Rest extends string}`
  ? IsEqual<First, Pivot> extends true
    ? Index
    : _IndexOfString<Rest, Pivot, Increment<Index>>
  : -1;

/**
 * Type version of `Array.prototype.indexOf()` and `String.prototype.indexOf()`. Returns the index of the second argument in the first argument
 * @example
 * ```ts
 * // 1
 * type Case1 = IndexOf<[1, 2, 3], 2>
 * // -1
 * type Case1 = IndexOf<[1, 2, 3], 4>
 * // 1
 * type Case3 = IndexOf<'123', '2'>
 * // -1
 * type Case4 = IndexOf<'123', '4'>
 * ```
 */
type IndexOf<
  T extends readonly unknown[] | string,
  Pivot extends T extends string ? string : unknown
> = T extends string
  ? IsStringLiteral<T> extends true
    ? _IndexOfString<T, Pivot>
    : never
  : T extends readonly unknown[]
  ? IsTuple<T> extends true
    ? _IndexOfArray<T, Pivot>
    : never
  : never;

/**
 * Returns a boolean whether the passed argument is a valid array index
 * @example
 * ```ts
 * // true
 * type Case1 = IsArrayIndex<1>
 * // true
 * type Case2 = IsArrayIndex<'1'>
 * // false
 * type Case3 = IsArrayIndex<-1>
 * ```
 */
type IsArrayIndex<T> = T extends number
  ? And<IsInteger<T>, IsGreaterOrEqual<T, 0>>
  : T extends string
  ? ParseNumber<T> extends infer NumT extends number
    ? Not<IsNever<NumT>> extends true
      ? And<IsInteger<NumT>, IsGreaterOrEqual<NumT, 0>>
      : false
    : false
  : never;

type PrettifyOptions = {
  recursive: boolean;
};

/**
 * Accepts a type and returns its simplified version for better readability. Transforms interface to type, simplifies intersections. If `recursive` option is `true` transforms the children object properties as well
 * @example
 * ```ts
 * // { a: string; b: string }
 * type Case1 = Prettify<{ a: string } & { b: string }
 * ```
 */
type Prettify<
  T,
  Options extends PrettifyOptions = { recursive: false }
> = T extends infer R
  ? {
      [K in keyof R]: If<Options["recursive"], Prettify<R[K], Options>, R[K]>;
    }
  : never;

type MutableOptions = {
  recursive: boolean;
};

/**
 * Make all properties in the passed argument mutable (removes readonly)
 * If `recursive` is set to `true`, it will also make all nested properties mutable
 * @example
 * ```ts
 * // { a: { readonly b: string } }
 * type Case1 = Mutable<{ readonly a: { readonly b: string } }>; 
 * // { a: { b: string } }
 * type Case2 = Mutable<{ readonly a: { readonly b: string } }, { recursive: true }>;
 * ```
 */
type Mutable<
  T,
  Options extends MutableOptions = { recursive: false }
> = Prettify<{
  -readonly [K in keyof T]: And<
    Options["recursive"],
    Extends<T[K], object>
  > extends true
    ? Mutable<T[K], Options>
    : T[K];
}>;

/**
 * Make passed properties in the passed argument mutable (removes readonly)
 * @example
 * ```ts
 * // { a: string; readonly b: string; }
 * type Case1 = MutableOnly<{ readonly a: string; readonly b: string; }, "a">;
 * // { a: string; b: string; }
 * type Case2 = MutableOnly<{ readonly a: string; readonly b: string; }, "a" | "b">;
 * ```
 */
type MutableOnly<T, K extends keyof T> = Prettify<
  Pick<T, Exclude<keyof T, K>> & {
    -readonly [P in K]: T[P];
  }
>;

/**
 * Make all properties in the passed argument mutable except for the passed properties
 * @example
 * ```ts
 * // { a: string; readonly b: string; }
 * type Case1 = MutableExcept<{ readonly a: string; readonly b: string; }, "b">;
 * // { a: string; b: string; }
 * type Case2 = MutableExcept<{ a: string; readonly b: string; }, "a">;
 * ```
 */
type MutableExcept<T, K extends keyof T> = Prettify<
  Pick<T, K> & {
    -readonly [P in Exclude<keyof T, K>]: T[P];
  }
>;

/**
 * Returns a boolean whether the passed argument is an array
 * @example
 * ```ts
 * // true
 * type Case1 = IsArray<[]>
 * // false
 * type Case2 = IsArray<string>
 * ```
 */
type IsArray<T> = AndArr<
  [Not<IsAny<T>>, Not<IsNever<T>>, Extends<T, readonly unknown[]>]
>;

/**
 * Returns a boolean whether the passed argument is a mutable array
 * @example
 * ```ts
 * // true
 * type Case1 = IsMutableArray<[]>
 * // false
 * type Case2 = IsMutableArray<readonly []>
 * ```
 */
type IsMutableArray<T> = And<IsArray<T>, NotExtends<Readonly<T>, T>>;

/**
 * Returns a boolean whether the passed argument is a read-only array
 * @example
 * ```ts
 * // true
 * type Case1 = IsReadonlyArray<readonly []>
 * // false
 * type Case2 = IsReadonlyArray<[]>
 * ```
 */
type IsReadonlyArray<T> = And<IsArray<T>, NotExtends<T, Mutable<T>>>;

/**
 * Returns the remainder of the division of two numbers.
 * @example
 * ```ts
 * // 1
 * type T0 = Mod<1, 2>;
 * // 1
 * type T1 = Mod<1, 3>;
 * ```
 */
type Mod<Dividend extends number, Divisor extends number> = Div<
  Dividend,
  Divisor
> extends infer Quotient extends number
  ? Mult<Quotient, Divisor> extends infer Product extends number
    ? Sub<Dividend, Product>
    : never
  : never;

/**
 * Accepts an integer argument and returns a boolean whether it is divisible by two. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // true
 * type Case1 = IsDivisibleByTwo<4>
 * // false
 * type Case2 = IsDivisibleByTwo<-1>
 * // true
 * type Case3 = IsDivisibleByTwo<-4>
 * ```
 */
type IsDivisibleByTwo<T extends number> = IsEven<T>;

type DivisibleByThreeMap = {
  3: true;
  6: true;
  9: true;
};

type _IsDivisibleByThree<T extends number> =
  DigitsTuple<T> extends infer Digits extends readonly number[]
    ? IsEqual<Digits["length"], 1> extends true
      ? Digits[0] extends keyof DivisibleByThreeMap
        ? true
        : false
      : SumArr<Digits> extends infer DigitsSum extends number
      ? IfLowerThan<DigitsSum, 3> extends true
        ? false
        : _IsDivisibleByThree<DigitsSum>
      : never
    : never;

/**
 * Accepts an integer argument and returns a boolean whether it is divisible by three. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // true
 * type Case1 = IsDivisibleByThree<123>
 * // false
 * type Case2 = IsDivisibleByThree<124>
 * // true
 * type Case3 = IsDivisibleByThree<-123>
 * ```
 */
type IsDivisibleByThree<T extends number> = _IsDivisibleByThree<T>;

/**
 * Accepts an integer argument and returns a boolean whether it is divisible by five. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // true
 * type Case1 = IsDivisibleByFive<125>
 * // false
 * type Case2 = IsDivisibleByFive<-13>
 * // true
 * type Case3 = IsDivisibleByFive<-125>
 * ```
 */
type IsDivisibleByFive<T extends number> = EndsWith<
  Stringify<T>,
  "0" | "5"
>;

/**
 * Accepts an integer argument and returns a boolean whether it is divisible by six. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // true
 * type Case1 = IsDivisibleBySix<126>
 * // false
 * type Case2 = IsDivisibleBySix<124>
 * // true
 * type Case3 = IsDivisibleBySix<-126>
 * ```
 */
type IsDivisibleBySix<T extends number> = And<
  IsDivisibleByTwo<T>,
  IsDivisibleByThree<T>
>;

/**
 * Accepts an integer argument and returns a boolean whether it is divisible by ten. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // true
 * type Case1 = IsDivisibleByTen<100>
 * // false
 * type Case2 = IsDivisibleByTen<101>
 * // true
 * type Case3 = IsDivisibleByTen<-100>
 * ```
 */
type IsDivisibleByTen<T extends number> = EndsWith<Stringify<T>, "0">;

/**
 * Accepts an integer argument and returns a boolean whether it is divisible by hundred. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // true
 * type Case1 = IsDivisibleByHundred<100>
 * // false
 * type Case2 = IsDivisibleByHundred<101>
 * // true
 * type Case3 = IsDivisibleByHundred<-100>
 * ```
 */
type IsDivisibleByHundred<T extends number> = EndsWith<
  Stringify<T>,
  "00"
>;

/**
 * Returns a boolean whether the first integer argument is divisible by the second integer argument
 * @example
 * ```ts
 * // true
 * type Case1 = IsDivisible<1024, 2>
 * // false
 * type Case2 = IsDivisible<1023, 2>
 * ```
 */
type IsDivisible<
  Dividend extends number,
  Divisor extends number
> = IsEqual<Mod<Dividend, Divisor>, 0>;

/**
 * Returns a boolean whether the passed argument is a letter (Only for letters that have both upper and lower case)
 * @example
 * ```ts
 * // true
 * type Case1 = IsLetter<'a'>
 * // false
 * type Case2 = IsLetter<'1'>
 * ```
 */
type IsLetter<T extends string> = Uppercase<T> extends Lowercase<T>
  ? false
  : true;

type _IsUnion<T, U = T> = IsNever<T> extends true
  ? false
  : T extends U
  ? Not<IsNever<Exclude<U, T>>>
  : false;

/**
 * Returns a boolean whether the passed argument is a union
 * @example
 * ```ts
 * // true
 * type Case1 = IsUnion<'a' | 'b'>
 * // false
 * type Case2 = IsUnion<'a'>
 * ```
 */
type IsUnion<T> = _IsUnion<T, T>;

/**
 * Accepts two integers and returns the maximum among them. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // 10
 * type Case1 = Max<1, 10>
 * // 1
 * type Case2 = Max<1, -10>
 * ```
 */
type Max<Num1 extends number, Num2 extends number> = IfLowerThan<
  Num1,
  Num2,
  Num2,
  Num1
>;

type _MaxArr<
  T extends readonly number[],
  CurrentMax extends number = ReturnItselfIfNotExtends<T[0], undefined, never>
> = IsEmptyArray<T> extends true
  ? CurrentMax
  : Shift<T, { includeRemoved: true }> extends [
      infer Rest extends number[],
      infer First extends number
    ]
  ? _MaxArr<Rest, Max<First, CurrentMax>>
  : never;

/**
 * Accepts an array of integers and returns the maximum among its elements. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // 10
 * type Case1 = MaxArr<[1, 2, 4, 10]>
 * // 4
 * type Case2 = MaxArr<[-1, 4, -10]>
 * ```
 */
type MaxArr<T extends readonly number[]> = IsTuple<T> extends true
  ? _MaxArr<T>
  : never;

/**
 * Accepts two integers and returns the minimum among them. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // 1
 * type Case1 = Min<1, 10>
 * // -10
 * type Case2 = Min<1, -10>
 * ```
 */
type Min<Num1 extends number, Num2 extends number> = IfLowerThan<
  Num1,
  Num2,
  Num1,
  Num2
>;

type _MinArr<
  T extends readonly number[],
  CurrentMin extends number = ReturnItselfIfNotExtends<T[0], undefined, never>
> = IsEmptyArray<T> extends true
  ? CurrentMin
  : Shift<T, { includeRemoved: true }> extends [
      infer Rest extends number[],
      infer First extends number
    ]
  ? _MinArr<Rest, Min<First, CurrentMin>>
  : never;

/**
 * Accepts an array of integers and returns the minimum among its elements. Range: `[Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]`
 * @example
 * ```ts
 * // 1
 * type Case1 = MinArr<[1, 2, 4, 10]>
 * // -10
 * type Case2 = MinArr<[-1, 4, -10]>
 * ```
 */
type MinArr<T extends readonly number[]> = IsTuple<T> extends true
  ? _MinArr<T>
  : never;

/**
 * Make all properties in the passed argument non-nullable
 * @example
 * ```ts
 * // { a: string, b: number }
 * type T0 = NonNullableObject<{ a: string | null, b: number | undefined }>;
 * ```
 */
type NonNullableObject<T> = {
  [K in keyof T]: NonNullable<T[K]>;
};

/**
 * Make passed properties in the passed argument non-nullable
 * @example
 * ```ts
 * // { a: string, b: number, c: boolean | null }
 * type T0 = NonNullableObjectOnly<{ a: string | null, b: number | undefined, c: boolean | null }, "a" | "b">;
 * ```
 */
type NonNullableObjectOnly<T, K extends keyof T> = Prettify<
  Pick<T, Exclude<keyof T, K>> & {
    [P in K]: NonNullable<T[P]>;
  }
>;

/**
 * Make all properties in the passed argument non-nullable except for the passed properties
 * @example
 * ```ts
 * // { a: string, b: number, c: boolean | null }
 * type T0 = NonNullableObjectExcept<{ a: string | null, b: number | undefined, c: boolean | null }, "c">;
 * ```
 */
type NonNullableObjectExcept<T, K extends keyof T> = Prettify<
  Pick<T, K> & {
    [P in Exclude<keyof T, K>]: NonNullable<T[P]>;
  }
>;

type _IsPalindrome<T extends string> = IsEmptyString<T> extends true
  ? true
  : Not<IsStringLiteral<T>> extends true
  ? false
  : T extends `${infer First extends string}${infer Rest extends string}`
  ? IsEmptyString<Rest> extends true
    ? true
    : Rest extends `${infer NewRest extends string}${First}`
    ? _IsPalindrome<NewRest>
    : false
  : false;

/**
 * Check whether a string or number is a palindrome.
 * @example
 * ```ts
 * // true
 * type T0 = IsPalindrome<"racecar">;
 * // false
 * type T1 = IsPalindrome<"hello">;
 * ```
 */
type IsPalindrome<T extends string | number> = _IsPalindrome<
  Stringify<T>
>;

/**
 * Returns a boolean if the passed type is `unknown`
 * @example
 * ```ts
 * // true
 * type TrueResult = IsUnknown<unknown>
 * // false
 * type FalseResult = IsUnknown<any>
 * ```
 */
type IsUnknown<T> = IsAny<T> extends true
  ? false
  : [unknown] extends [T]
  ? true
  : false;

/**
 * Returns the second argument if the first argument is `unknown` (defaults to `true`), otherwise returns the third argument (defaults to `false`)
 * @example
 * ```ts
 * // "foo"
 * type Result = IfUnknown<unknown, "foo", "bar">
 * ```
 */
type IfUnknown<T, IfTrue = true, IfFalse = false> = If<
  IsUnknown<T>,
  IfTrue,
  IfFalse
>;

type UnknownifyPropertiesOptions = {
  makeOptional: boolean;
};

/**
 * Turns all properties of an object to type `unknown`.
 * If `makeOptional` option is `true`, makes all properties optional
 * @example
 * ```ts
 * // {a:unknown; b:unknown}
 * type Result = UnknownifyProperties<{a: string; b: string}>
 * ```
 */
type UnknownifyProperties<
  T extends object,
  Options extends UnknownifyPropertiesOptions = { makeOptional: false }
> = {
  [K in keyof T]: unknown;
} extends infer Result
  ? If<Options["makeOptional"], Partial<Result>, Result>
  : never;

type OverWritable = {
  overwriteDefault?: boolean;
};

type ApplyDefaultOptions<
  BaseOptions,
  Options extends BaseOptions,
  DefaultOptions extends BaseOptions,
  OverwriteRules,
  OverwriteDefault extends boolean = false
> = Prettify<{
  [K in keyof BaseOptions]-?: K extends keyof Options
    ? AndArr<
        [
          Extends<NonNullable<BaseOptions[K]>, object>,
          Not<IsNever<DefaultOptions[K]>>,
          Not<IsUnknown<BaseOptions[K]>>
        ]
      > extends true
      ? ApplyDefaultOptions<
          NonNullable<BaseOptions[K]>,
          Options[K],
          DefaultOptions[K],
          OverwriteRules[K & keyof OverwriteRules],
          OverwriteDefault
        > & {
          tra: "test";
        }
      : Or<
          IsEqual<OverwriteDefault, true>,
          And<
            Extends<K, keyof OverwriteRules>,
            Extends<OverwriteRules[K & keyof OverwriteRules], true>
          >
        > extends true
      ? Options[K]
      : Options[K] | DefaultOptions[K]
    : DefaultOptions[K];
}>;

/**
 * Get the values of properties in an object
 * @example
 * ```ts
 * // string | number
 * type T0 = ValueOf<{ a: string, b: number }>;
 * ```
 */
type ValueOf<T> = T[keyof T];

/**
 * Get the values of properties in an object only for the passed properties
 * @example
 * ```ts
 * // string
 * type T0 = ValueOfOnly<{ a: string, b: number }, "a">;
 * ```
 */
type ValueOfOnly<T, K extends keyof T> = T[K];

/**
 * Get the values of properties in an object except for the passed properties
 * @example
 * ```ts
 * // number
 * type T0 = ValueOfExcept<{ a: string, b: number }, "a">;
 * ```
 */
type ValueOfExcept<T, K extends keyof T> = T[keyof Omit<T, K>];

/**
 * Get the types of elements in an array
 * @example
 * ```ts
 * // string | number
 * type T0 = ValueOfArray<[string, number]>;
 * ```
 */
type ValueOfArray<T extends readonly unknown[]> = T[number];

type PathToFieldsOptions = OverWritable & {
  ignoredTypes?: unknown;
  stopTypes?: unknown;
  limit?: number;
  format?: "dot" | "array";
  ignoredKeys?: PropertyKey;
  arrayIndexing?: {
    exactIndexes: boolean;
  };
};

type DefaultPathToFieldsOptions = {
  ignoredTypes: never;
  stopTypes: string | number | boolean | symbol | Date | Function;
  format: "dot";
  limit: 10;
  ignoredKeys: never;
  arrayIndexing: {
    exactIndexes: false;
  };
};

type OverwriteRules = {
  limit: true;
  format: true;
  arrayIndexing: {
    exactIndexes: true;
  };
};

type _PathToFieldsArray<
  T extends readonly unknown[],
  Options extends PathToFieldsOptions,
  Iteration extends number = 0
> = And<
  IsTuple<T>,
  IsEqual<Options["arrayIndexing"]["exactIndexes"], true>
> extends true
  ? ValueOfArray<{
      [K in keyof T]: IsArrayIndex<K> extends true
        ? [K, ..._PathToFields<T[K], Options, Increment<Iteration>>]
        : never;
    }>
  : ArrayElementType<T> extends infer ElementType
  ? [
      `${number}`,
      ...(ElementType extends ElementType
        ? _PathToFields<ElementType, Options, Increment<Iteration>>
        : never)
    ]
  : never;

type _PathToFields<
  T,
  Options extends PathToFieldsOptions,
  Iteration extends number = 0
> = T extends Options["ignoredTypes"]
  ? never
  : T extends Options["stopTypes"]
  ? []
  : IsEqual<Iteration, Options["limit"]> extends true
  ? never
  : T extends readonly unknown[]
  ? _PathToFieldsArray<T, Options, Iteration>
  : ValueOf<{
      [K in Exclude<keyof T, symbol | Options["ignoredKeys"]>]: NonNullable<
        T[K]
      > extends infer NonNullableFields
        ? NonNullableFields extends readonly unknown[]
          ? [K, ..._PathToFieldsArray<NonNullableFields, Options, Iteration>]
          : [
              K,
              ..._PathToFields<NonNullableFields, Options, Increment<Iteration>>
            ]
        : never;
    }>;

/**
 * Get all possible paths to fields in an object
 * @example
 * ```ts
 * // "a" | "b" | "d"
 * type T0 = PathToFields<{a: string, b: number, d: boolean}>;
 * // ["arr.0.a", "arr.0.b", "arr.1.c"]
 * type T1 = PathToFields<{arr: [{a: string; b: number}, {c: boolean}]}, {
 *  arrayIndexing: {
 *   exactIndexes: true;
 *  }
 * }>;
 * ```
 */
type PathToFields<
  T,
  Options extends PathToFieldsOptions & { overwriteDefault?: boolean } = never
> = (
  IsNever<Options> extends true
    ? DefaultPathToFieldsOptions
    : ApplyDefaultOptions<
        Omit<PathToFieldsOptions, keyof OverWritable>,
        Options,
        DefaultPathToFieldsOptions,
        OverwriteRules,
        PathToFieldsOptions["overwriteDefault"]
      >
) extends infer MergedOptions extends PathToFieldsOptions
  ? _PathToFields<T, MergedOptions> extends infer Paths extends readonly (
      | string
      | number
    )[]
    ? IsEqual<MergedOptions["format"], "dot"> extends true
      ? Paths extends Paths
        ? Join<Paths, ".">
        : never
      : Paths
    : never
  : never;

/**
 * Make passed properties in the passed argument optional
 * @example
 * ```ts
 * // { a?: string, b: number }
 * type T0 = PartialOnly<{ a: string, b: number }, 'a'>;
 * ```
 */
type PartialOnly<T extends object, K extends keyof T> = Prettify<
  Pick<T, Exclude<keyof T, K>> & {
    [P in K]?: T[P];
  }
>;

/**
 * Make all properties in the passed argument optional except for the passed properties
 * @example
 * ```ts
 * // { a: string, b?: number }
 * type T0 = PartialExcept<{ a: string, b: number }, 'a'>;
 * ```
 */
type PartialExcept<T extends object, K extends keyof T> = Prettify<
  Pick<T, K> & {
    [P in Exclude<keyof T, K>]?: T[P];
  }
>;

type _Pow<
  Num extends number,
  Factor extends number,
  CurrentProduct extends number = 1,
  Iteration extends unknown[] = []
> = IsEqual<Iteration["length"], Factor> extends true
  ? CurrentProduct
  : _Pow<Num, Factor, Mult<CurrentProduct, Num>, Push<Iteration, unknown>>;

/**
 * Returns the first integer parameter raised to factor of the second integer parameter
 *
 * @example
 * ```ts
 * // 100
 * type Result = Pow<10, 2>
 * ```
 */
type Pow<Num extends number, Factor extends number> = _Pow<Num, Factor>;

/**
 * Make passed properties in the passed argument readonly
 * @example
 * ```ts
 * // { readonly a: string, b: number }
 * type T0 = ReadonlyOnly<{ a: string, b: number }, 'a'>;
 * ```
 */
type ReadonlyOnly<T extends object, K extends keyof T> = Prettify<
  Pick<T, Exclude<keyof T, K>> & {
    readonly [P in K]: T[P];
  }
>;

/**
 * Make all properties in the passed argument readonly except for the passed properties
 * @example
 * ```ts
 * // { a: string, readonly b: number }
 * type T0 = ReadonlyExcept<{ a: string, b: number }, 'a'>;
 * ```
 */
type ReadonlyExcept<T extends object, K extends keyof T> = Prettify<
  Pick<T, K> & {
    readonly [P in Exclude<keyof T, K>]: T[P];
  }
>;

/**
 * Removes the index signature from the passed type
 * @example
 * ```ts
 * // {}
 * type Case1 = RemoveIndexSignature<{[x: string]: number}>
 * // {x: number}
 * type Case2 = RemoveIndexSignature<{x: number}>
 * ```
 */
type RemoveIndexSignature<T> = {
  [Key in keyof T as Key extends `${infer _}` ? Key : never]: T[Key];
};

/**
 * Replaces all occurrences of the second string argument with the third string argument in the first string argument
 * @example
 * ```ts
 * // 'remove him him'
 * type Case1 = ReplaceAll<'remove me me', 'me', 'him'>
 * // 'remove me me'
 * type Case2 = ReplaceAll<'remove me me', 'us', 'him'>
 * ```
 */
type ReplaceAll<
  T extends string,
  Pivot extends string,
  ReplaceBy extends string
> = T extends `${infer A}${Pivot}${infer B}`
  ? ReplaceAll<`${A}${ReplaceBy}${B}`, Pivot, ReplaceBy>
  : T;

/**
 * Replaces the first occurrence of the second string argument with the third string argument in the first string argument
 * @example
 * ```ts
 * // 'remove him me'
 * type Case1 = Replace<'remove me me', 'me', 'him'>
 * // 'remove me me'
 * type Case2 = Replace<'remove me me', 'us', 'him'>
 * ```
 */
type Replace<
  T extends string,
  Pivot extends string,
  ReplaceBy extends string
> = T extends `${infer A}${Pivot}${infer B}` ? `${A}${ReplaceBy}${B}` : T;

/**
 * Make passed properties in the passed argument required
 * @example
 * ```ts
 * // { a: number; b?: string; c?: boolean }
 * type T0 = RequiredOnly<{ a?: number; b?: string; c?: boolean }, "a">;
 * ```
 */
type RequiredOnly<T extends object, K extends keyof T> = Prettify<
  Pick<T, Exclude<keyof T, K>> & {
    [P in K]-?: T[P];
  }
>;

/**
 * Make all properties in the passed argument required except for the passed properties
 * @example
 * ```ts
 * // { a?: number; b: string; c: boolean }
 * type T0 = RequiredExcept<{ a?: number; b?: string; c?: boolean }, "a">;
 * ```
 */
type RequiredExcept<T extends object, K extends keyof T> = Prettify<
  Pick<T, K> & {
    [P in Exclude<keyof T, K>]-?: T[P];
  }
>;

type _Reverse<
  T extends readonly unknown[],
  Result extends readonly unknown[] = []
> = IsEmptyArray<T> extends true
  ? Result
  : T extends readonly [...infer Rest extends readonly unknown[], infer First]
  ? _Reverse<Rest, [...Result, First]>
  : Result;

/**
 * Returns a new array with the elements in reverse order.
 * @example
 * ```ts
 * // [3, 2, 1]
 * type T0 = Reverse<[1, 2, 3]>;
 * // [3, 2, 1]
 * type T1 = Reverse<readonly [1, 2, 3]>;
 * ```
 */
type Reverse<T extends readonly unknown[]> = IsTuple<T> extends true
  ? _Reverse<T> extends infer R extends readonly unknown[]
    ? IsReadonlyArray<T> extends true
      ? Readonly<R>
      : R
    : never
  : T;

/**
 * Type version of `Math.round()`. Returns the value of a number rounded to the nearest integer
 * @example
 * ```ts
 * // 3
 * type T0 = Round<3.14>;
 * // -3
 * type T1 = Round<-3.14>;
 * ```
 */
type Round<T extends number> = IsFloat<T> extends true
  ? GetFloatNumberParts<T> extends [
      infer Whole extends number,
      infer Fraction extends number
    ]
    ? IsGreaterThan<FirstDigit<Fraction>, 4> extends true
      ? Increment<Whole>
      : Whole
    : never
  : T;

type SliceRemovedItemValue = Record<"__type-samurai_internal__", symbol>;

type FilterRemoved<
  T extends readonly unknown[],
  Result extends unknown[] = []
> = T extends readonly [infer First, ...infer Rest extends unknown[]]
  ? FilterRemoved<
      Rest,
      First extends SliceRemovedItemValue ? Result : Push<Result, First>
    >
  : Result;

/**
 * Type version of `Array.prototype.slice()` method. Returns a shallow copy of a portion of an array into a new array object selected from `start` to `end` (`end` not included)
 * @example
 * ```ts
 * // [2, 3]
 * type T0 = Slice<[1, 2, 3, 4], 1>;
 * // [2, 3]
 * type T1 = Slice<[1, 2, 3, 4], 1, 3>;
 * ```
 */
type Slice<
  T extends readonly unknown[],
  Start extends number = 0,
  End extends number = T["length"]
> = (
  IsEmptyArray<T> extends true
    ? "self"
    : IsGreaterOrEqual<Start, T["length"]> extends true
    ? "empty"
    : IsNegative<End> extends true
    ? IsGreaterOrEqual<Abs<End>, T["length"]> extends true
      ? "empty"
      : [
          IfPositive<Start, Start, Sum<T["length"], Start>>,
          Sum<T["length"], End>
        ]
    : And<
        Or<IsEqual<Start, 0>, IsGreaterOrEqual<Abs<Start>, T["length"]>>,
        IsGreaterOrEqual<End, T["length"]>
      > extends true
    ? "self"
    : [IfPositive<Start, Start, Sum<T["length"], Start>>, End]
) extends infer Indexes
  ? Indexes extends "self"
    ? T
    : Indexes extends "empty"
    ? []
    : Indexes extends [
        infer NewStart extends number,
        infer NewEnd extends number
      ]
    ? IfGreaterOrEqual<NewStart, NewEnd> extends true
      ? []
      : FilterRemoved<{
          [K in keyof T]: IsArrayIndex<K> extends true
            ? If<
                And<
                  IsGreaterOrEqual<ParseNumber<K>, NewStart>,
                  IsLowerThan<ParseNumber<K>, NewEnd>
                >,
                T[K],
                SliceRemovedItemValue
              >
            : T[K];
        }>
    : T
  : T;

/**
 * Swaps the position of two elements in a tuple.
 * @example
 * ```ts
 * // [3, 2, 1]
 * type Case1 = Swap<[1, 2, 3], 0, 2>;
 * // [1, 2, 3]
 * type Case2 = Swap<[1, 2, 3], 0, 0>;
 * ```
 */
type Swap<
  T extends readonly unknown[],
  FromIndex extends number,
  ToIndex extends number
> = IsTuple<T> extends true
  ? And<
      IsBetween<FromIndex, 0, T["length"]>,
      IsBetween<ToIndex, 0, T["length"]>
    > extends true
    ? T[FromIndex] extends infer From
      ? T[ToIndex] extends infer To
        ? {
            [K in keyof T]: ParseNumber<K> extends infer NumK
              ? IsEqual<FromIndex, NumK> extends true
                ? To
                : IsEqual<ToIndex, NumK> extends true
                ? From
                : T[K]
              : never;
          }
        : never
      : never
    : never
  : T;

type _SortSingle<
  Result extends readonly number[],
  PivotIndex extends number,
  CurrentIndex extends number
> = IsEqual<PivotIndex, CurrentIndex> extends true
  ? Result
  : Increment<CurrentIndex> extends infer NextCurrentIndex extends number
  ? _SortSingle<
      IsGreaterThan<Result[CurrentIndex], Result[NextCurrentIndex]> extends true
        ? Swap<
            Result,
            CurrentIndex,
            NextCurrentIndex
          > extends infer NewResult extends readonly number[]
          ? NewResult
          : Result
        : Result,
      PivotIndex,
      NextCurrentIndex
    >
  : never;

type _Sort<
  T extends readonly number[],
  CurrentIndex extends number
> = IsLowerOrEqual<CurrentIndex, 0> extends true
  ? T
  : _SortSingle<T, CurrentIndex, 0> extends infer NewT extends readonly number[]
  ? _Sort<NewT, Decrement<CurrentIndex>>
  : T;

/**
 * Sorts a tuple of numbers in ascending order.
 * @example
 * ```ts
 * // [1, 2, 3]
 * type T0 = Sort<[3, 2, 1]>;
 * 
 * // [-1, 0, 1]
 * type T1 = Sort<[1, -1, 0]>;
 * ```
*/
type Sort<T extends readonly number[]> = IsLowerThan<
  T["length"],
  2
> extends true
  ? T
  : _Sort<T, Decrement<T["length"]>>;

/**
 * Returns a boolean whether the first string arguments starts with the second string argument
 * @example
 * ```ts
 * // true
 * type Case1 = StartsWith<'abc', 'a'>
 * // false
 * type Case2 = StartsWith<'abc', 'b'>
 * ```
 */
type StartsWith<
  Str extends string,
  Pivot extends string | number
> = Str extends `${Pivot}${string}` ? true : false;

/**
 * Type version of switch statement.
 * @param Cases - An object containing cases with their corresponding values.
 * @param Default - The default value if the condition does not match any case.
 * @example
 * ```ts
 * const a = 'const';
 *
 * // 'bar'
 * type Result = Switch<typeof a, { number: 'foo', const: 'bar' }, 'foobar'>
 *
 * ```
 */
type Switch<
  Condition extends PropertyKey,
  Cases extends Record<PropertyKey, unknown>,
  Default = never
> = Condition extends keyof Cases ? Cases[Condition] : Default;

/**
 * Turns accepted literal type argument to its primitive
 * @example
 * ```ts
 * // number
 * type Case1 = ToPrimitive<1>
 * // string
 * type Case2 = ToPrimitive<'1'>
 * // {a: number; b: string}
 * type Case3 = ToPrimitive<{a: 1;  b: 's'}>
 * ```
 */
type ToPrimitive<T> = 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<T[K]>;
    };

/**
 * Type version of `Math.trunc()`. Returns the integer part of a number by removing any fractional digits.
 * @example
 * ```ts
 * // 3
 * type T0 = Trunc<3.14>;
 * // -3
 * type T1 = Trunc<-3.14>;
 * ```
 */
type Trunc<T extends number> = number extends T
  ? T
  : IsFloat<T> extends true
  ? GetFloatNumberParts<T>[0] extends infer IntegerPart extends number
    ? IsNegative<T> extends true
      ? Negate<IntegerPart>
      : IntegerPart
    : never
  : T;

/**
 * Accepts a tuple of string, number or symbol and return the object type, where the key values are the elements of the tuple
 * @example
 * ```ts
 * // {
 * //   foo: 'foo',
 * //   bar: 'bar',
 * // }
 * type Result = TupleToObject<['foo', 'bar']>
 * ```
 */
type TupleToObject<T extends readonly PropertyKey[]> = {
  [K in T[number]]: K;
};

/**
 * Turns the passed union type to an intersection
 * Reference: https://stackoverflow.com/a/50375286/21637817
 * @example
 * ```ts
 * // {a: string} & {b: string}
 * type Case1 = UnionToIntersection<{a: string} | {b: string}>
 * ```
 */
type UnionToIntersection<U> = (
  U extends any ? (k: U) => void : never
) extends (k: infer I) => void
  ? I
  : never;

/**
 * Adds the second argument to the beginning of the first array argument.
 * @example
 * ```ts
 * // ['foo', 'bar']
 * type Result = Unshift<['bar'], 'foo'>
 * ```
 */
type Unshift<T extends readonly unknown[], U> = [U, ...T];

type Minus<A extends number, B extends number> = Sum<A, Negate<B>>;

export type { Abs, And, AndArr, AnifyProperties, AnifyPropertiesOptions, AreAnagrams, ArrayElementType, Ceil, Color, ColorOptions, CompareNumberLength, CompareStringLength, Concat, Decrement, DefaultColorOptions, DefaultHSLOptions, DefaultRGBOptions, DigitsTuple, Div, Dot, EmptyArray, EmptyString, EndsWith, Even, Extends, ExtendsArr, Factorial, Fibonacci, FirstCharacter, FirstCharacterOptions, FirstDigit, Float, Floor, GetFloatNumberParts, HEX, HSL, HSLOptions, If, IfAny, IfColor, IfEmptyArray, IfEmptyString, IfEqual, IfEven, IfExtends, IfFloat, IfGreaterOrEqual, IfGreaterThan, IfHEX, IfHSL, IfInteger, IfLowerThan, IfNegative, IfNegativeFloat, IfNegativeInteger, IfNever, IfNonEmptyArray, IfNonEmptyString, IfNot, IfNotEqual, IfNotExtends, IfOdd, IfPositive, IfPositiveFloat, IfPositiveInteger, IfRGB, IfUnknown, Includes, Increment, IndexOf, Integer, IsAny, IsArray, IsArrayIndex, IsBetween, IsColor, IsDivisible, IsDivisibleByFive, IsDivisibleByHundred, IsDivisibleBySix, IsDivisibleByTen, IsDivisibleByThree, IsDivisibleByTwo, IsEmptyArray, IsEmptyString, IsEqual, IsEven, IsFloat, IsGreaterOrEqual, IsGreaterThan, IsHEX, IsHSL, IsInteger, IsLetter, IsLongerNumber, IsLongerString, IsLowerThan, IsMutableArray, IsNegative, IsNegativeFloat, IsNegativeInteger, IsNever, IsNonEmptyArray, IsNonEmptyString, IsNotEqual, IsOdd, IsPalindrome, IsPositive, IsPositiveFloat, IsPositiveInteger, IsRGB, IsReadonlyArray, IsSameLengthNumber, IsSameLengthString, IsShorterNumber, IsShorterString, IsStringLiteral, IsTuple, IsUnion, IsUnknown, Join, LastCharacter, LastCharacterOptions, Max, MaxArr, Min, MinArr, Minus, Mod, Mult, Mutable, MutableExcept, MutableOnly, Negate, Negative, NegativeFloat, NegativeInteger, NeverifyProperties, NeverifyPropertiesOptions, NonEmptyArray, NonEmptyString, NonNullableObject, NonNullableObjectExcept, NonNullableObjectOnly, Not, NotExtends, NumberLength, Odd, Or, OrArr, ParseNumber, PartialExcept, PartialOnly, PathToFields, PathToFieldsOptions, Pop, PopOptions, Positive, PositiveFloat, PositiveInteger, Pow, Prettify, PrettifyOptions, Push, RGB, RGBOptions, ReadonlyExcept, ReadonlyOnly, RemoveIndexSignature, RemoveLeading, Repeat, Replace, ReplaceAll, RequiredExcept, RequiredOnly, ReturnItselfIfExtends, ReturnItselfIfNotExtends, Reverse, Round, Shift, ShiftOptions, Slice, Sort, Split, StartsWith, StringLength, Stringify, Sub, Sum, SumArr, Swap, Switch, ToPrimitive, Trunc, TupleToObject, UnionToIntersection, UnknownifyProperties, UnknownifyPropertiesOptions, Unshift, ValueOf, ValueOfArray, ValueOfExcept, ValueOfOnly };
