import type { Equal, Expect } from '@type-challenges/utils' type casesGreaterThan = [ Expect, true>>, Expect, true>>, Expect, false>>, Expect, false>>, Expect, true>>, Expect, false>>, Expect, false>>, Expect, true>>, Expect, true>>, ] type casesGreaterDigit = [ Expect, false>>, Expect, false>>, Expect, true>>, Expect, true>>, Expect, true>>, Expect, true>>, Expect, false>>, Expect, false>>, ] type casesExclusiveRange = [ Expect, []>>, Expect, [0]>>, Expect, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>, Expect, [0, 1, 2, 3, 4]>>, ] type casesExcludeDigitsUntil = [ Expect, '3' | '4' | '5' | '6' | '7' | '8' | '9'>>, Expect, '8' | '9'>>, Expect, never>>, ] // Naive implementation of GreaterThan, // runs in O(N) where N is the smaller number // because of the recursion limit, // it can't handle numbers larger than 999 type NaiveGreaterThan< T extends number, U extends number, Acc extends 1[] = [] > = // Check if Acc is same as T Acc['length'] extends T // Check if T is U ? Acc['length'] extends U // T == U ? false // T < U : false // Check if Acc is first at U : Acc['length'] extends U // T > U ? true // Recurse to the next number : NaiveGreaterThan ; // Digits as string union type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; // Create an exclusive range/tuple up until T // Runs in O(N) type ExclusiveRange< N extends number, Range extends number[] = [], Acc extends 1[] =[], > = Range['length'] extends N ? Range : ExclusiveRange< N, [...Range, Acc['length']], [...Acc, 1] > ; // Digit type without the numbers 0 up until but not including U type ExcludeDigitsUntil< N extends number, Digits extends Digit = Digit, Range extends number[] = ExclusiveRange, > = Digits extends `${Range[number]}` ? never : Digits // Check T is greater than U type GreaterDigit< T extends Digit, U extends Digit, > = T extends '0' ? false : T extends '1' ? U extends ExcludeDigitsUntil<1> ? false : true : T extends '2' ? U extends ExcludeDigitsUntil<2> ? false : true : T extends '3' ? U extends ExcludeDigitsUntil<3> ? false : true : T extends '4' ? U extends ExcludeDigitsUntil<4> ? false : true : T extends '5' ? U extends ExcludeDigitsUntil<5> ? false : true : T extends '6' ? U extends ExcludeDigitsUntil<6> ? false : true : T extends '7' ? U extends ExcludeDigitsUntil<7> ? false : true : T extends '8' ? U extends ExcludeDigitsUntil<8> ? false : true : T extends '9' ? U extends ExcludeDigitsUntil<9> ? false : true : never ; // Compare each digit until there is one digit that is greater or smaller type GreaterString< T extends string, U extends string > = T extends `${infer THead}${infer TTail}` ? U extends `${infer UHead}${infer UTail}` // If both T and U have a Digit in front, compare it ? GreaterDigit extends false // If not greater, compare the rest of the digits ? GreaterString : true : false : false ; // Compare the length of both strings, // if they have the same length compare each digit type GreaterStringLength< T extends string, U extends string > = T extends `${Digit}${infer R1}` // T has another digit in front ? U extends `${Digit}${infer R2}` // U has another digit in front ? GreaterStringLength // U ran out of digits : true // T ran out of digits, either U runs out too or U has more digits, // either way GreaterThan returns false : false ; // Runs in O(log(min(N, M)) because it needs to check every digit of the smaller number type GreaterThan< N extends number, M extends number > = GreaterStringLength<`${N}`, `${M}`> extends true ? true : GreaterString<`${N}`, `${M}`> ;