diff --git a/greater-than.ts b/greater-than.ts new file mode 100644 index 0000000..9b9c836 --- /dev/null +++ b/greater-than.ts @@ -0,0 +1,176 @@ +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>>, +] + +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 +; + +type X = GreaterString<'8', '5'>; + +// 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}`> +;