import { Decrement, _Decrement } from "./decrement"; import { LastCharacter } from "./last-character"; import { IsLowerThan } from "./lower-than"; import { Abs, IsNegativeInteger, Negate, ParseNumber } from "./number"; import { RemoveLeading } from "./remove-leading"; import { IfEmptyString, IsEmptyString } from "./string"; import { Stringify } from "./stringify"; import { Sum } from "./sum"; type SubDecrementMap = { "-9": -10; "-8": -9; "-7": -8; "-6": -7; "-5": -6; "-4": -5; "-3": -4; "-2": -3; "-1": -2; "0": -1; "1": 0; "2": 1; "3": 2; "4": 3; "5": 4; "6": 5; "7": 6; "8": 7; "9": 8; }; type SubNegativeCarryMap = { "-10": 0; "-9": 1; "-8": 2; "-7": 3; "-6": 4; "-5": 5; "-4": 6; "-3": 7; "-2": 8; "-1": 9; }; type SubMap = { 0: [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]; 1: [1, 0, -1, -2, -3, -4, -5, -6, -7, -8]; 2: [2, 1, 0, -1, -2, -3, -4, -5, -6, -7]; 3: [3, 2, 1, 0, -1, -2, -3, -4, -5, -6]; 4: [4, 3, 2, 1, 0, -1, -2, -3, -4, -5]; 5: [5, 4, 3, 2, 1, 0, -1, -2, -3, -4]; 6: [6, 5, 4, 3, 2, 1, 0, -1, -2, -3]; 7: [7, 6, 5, 4, 3, 2, 1, 0, -1, -2]; 8: [8, 7, 6, 5, 4, 3, 2, 1, 0, -1]; 9: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]; }; type _RemoveLeadingZeros = ParseNumber< RemoveLeading extends infer WithoutLeadingZeros extends string ? IfEmptyString : never >; export type _Sub< Num1 extends string, Num2 extends string, NegativeCarry extends 0 | 1 = 0, Result extends string = "" > = IsEmptyString extends true ? NegativeCarry extends 0 ? `${Num1}${Result}` : `${Decrement>}${Result}` : LastCharacter extends `${infer Num1LastDigit extends keyof SubMap & number}` ? LastCharacter extends `${infer Num2LastDigit extends keyof SubMap[Num1LastDigit] & number}` ? `${SubMap[Num1LastDigit][Num2LastDigit]}` extends infer DigitsSub extends keyof SubDecrementMap ? ( NegativeCarry extends 1 ? Stringify : DigitsSub ) extends infer DigitsSubWithCarry extends string ? Num1 extends `${infer Num1Rest}${Num1LastDigit}` ? Num2 extends `${infer Num2Rest}${Num2LastDigit}` ? DigitsSubWithCarry extends keyof SubNegativeCarryMap ? _Sub< Num1Rest, Num2Rest, 1, `${SubNegativeCarryMap[DigitsSubWithCarry]}${Result}` > : _Sub : 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> * ``` */ export type Sub< Num1 extends number, Num2 extends number > = IsNegativeInteger extends true ? IsNegativeInteger extends true ? IsLowerThan extends true ? Negate< _RemoveLeadingZeros<_Sub>, Stringify>>> > : _RemoveLeadingZeros<_Sub>, Stringify>>> : Sum, Num2> extends infer Result extends number ? Negate : never : IsNegativeInteger extends true ? Sum> : IsLowerThan extends true ? Negate<_RemoveLeadingZeros<_Sub, Stringify>>> : _RemoveLeadingZeros<_Sub, Stringify>>;