type GetResult<T extends Comparison[]> = T extends [infer First, ...infer Rest extends Comparison[]]
? First extends Comparison.Equal
? GetResult<Rest>
: First
: Comparison.Equal
type CompareDigit<A extends number, B extends number, Acc extends 0[] = []> = A extends B
? Comparison.Equal
: Acc['length'] extends A
? Comparison.Lower
: Acc['length'] extends B
? Comparison.Greater
: CompareDigit<A, B, [...Acc, 0]>
type ComparePositive<A extends string, B extends string, Acc extends Comparison[] = []> =
`${A}${B}` extends ''
? GetResult<Acc>
: A extends '' ? Comparison.Lower
: B extends '' ? Comparison.Greater
: [A, B] extends [`${infer AFirst extends number}${infer ARest}`, `${infer BFirst extends number}${infer BRest}`]
? ComparePositive<ARest, BRest, [...Acc, CompareDigit<AFirst, BFirst>]>
: never
type Comparator<A extends number, B extends number> =
`${A}${B}` extends `-${infer A1}-${infer B1}`
? ComparePositive<B1, A1>
: `${A}` extends `-${number}`
? Comparison.Lower
: `${B}` extends `-${number}`
? Comparison.Greater
: ComparePositive<`${A}`, `${B}`>
Solution by 2083335157 #35119
type ReverseString<S extends string> = S extends `${infer First}${infer Rest}` ? `${ReverseString<Rest>}${First}` : "";
type TupleOfLength<N extends number, Result extends 0[] = []> = Result["length"] extends N
? Result
: TupleOfLength<N, [...Result, 0]>;
type CompareDigit<StrL extends string, StrR extends string> = StrL extends StrR
? Comparison.Equal
: StrL extends `${infer L extends number}`
? StrR extends `${infer R extends number}`
? TupleOfLength<L> extends [...TupleOfLength<R>, ...unknown[]]
? Comparison.Greater
: Comparison.Lower
: never
: never;
type CompareAbsolute<
A extends string,
B extends string,
Previous extends Comparison = Comparison.Equal
> = A extends `${infer FirstA}${infer RestA}`
? B extends `${infer FirstB}${infer RestB}`
? CompareAbsolute<
RestA,
RestB,
CompareDigit<FirstA, FirstB> extends infer R extends Comparison
? R extends Comparison.Equal
? Previous
: R
: never
>
: Comparison.Greater
: B extends `${infer _}${infer _}`
? Comparison.Lower
: Previous;
type Comparator<
A extends number,
B extends number,
AbsA extends number = `${A}` extends `-${infer Abs extends number}` ? Abs : A,
AbsB extends number = `${B}` extends `-${infer Abs extends number}` ? Abs : B,
AbsComparison extends Comparison = CompareAbsolute<ReverseString<`${AbsA}`>, ReverseString<`${AbsB}`>>
> = `${A}` extends `-${number}`
? `${B}` extends `-${number}`
? AbsComparison extends Comparison.Lower
? Comparison.Greater
: AbsComparison extends Comparison.Greater
? Comparison.Lower
: Comparison.Equal
: Comparison.Lower
: `${B}` extends `-${number}`
? Comparison.Greater
: AbsComparison;
Solution by yukicountry #34537
type ParseInt<T extends string> = T extends `${infer Digit extends number}`
? Digit
: never;
type ReverseString<S extends string> = S extends `${infer First}${infer Rest}`
? `${ReverseString<Rest>}${First}`
: "";
type RemoveLeadingZeros<S extends string> = S extends "0"
? S
: S extends `${"0"}${infer R}`
? RemoveLeadingZeros<R>
: S;
type InternalMinusOne<S extends string> =
S extends `${infer Digit extends number}${infer Rest}`
? Digit extends 0
? `9${InternalMinusOne<Rest>}`
: `${[9, 0, 1, 2, 3, 4, 5, 6, 7, 8][Digit]}${Rest}`
: never;
type MinusOne<T extends number> = T extends 0
? -1
: ParseInt<
RemoveLeadingZeros<ReverseString<InternalMinusOne<ReverseString<`${T}`>>>>
>;
type InnerGreaterThan<T extends number, U extends number> = T extends U
? true
: T extends 0
? false
: InnerGreaterThan<MinusOne<T>, U>;
type GreaterThan<T extends number, U extends number> = T extends U
? false
: U extends 0
? true
: InnerGreaterThan<T, U>;
type LengthOfString<
S extends string,
T extends string[] = []
> = S extends `${infer F}${infer R}`
? LengthOfString<R, [...T, F]>
: T["length"];
type PositiveGreaterThan<T extends string, U extends string> = GreaterThan<
LengthOfString<T>,
LengthOfString<U>
> extends true
? true
: GreaterThan<LengthOfString<U>, LengthOfString<T>> extends true
? false
: [T, U] extends [
`${infer F1 extends number}${infer R1}`,
`${infer F2 extends number}${infer R2}`
]
? F1 extends F2
? PositiveGreaterThan<R1, R2>
: GreaterThan<F1, F2>
: [T, U] extends [`${infer F1 extends number}`, `${infer F2 extends number}`]
? GreaterThan<F1, F2>
: false;
type NegativeGreaterThan<
T extends number,
U extends number
> = `${T}` extends `-${infer T1}`
? `${U}` extends `-${infer U1}`
? PositiveGreaterThan<U1, T1>
: false
: `${U}` extends `-${string}`
? true
: PositiveGreaterThan<`${T}`, `${U}`>;
enum Comparison {
Greater,
Equal,
Lower,
}
type Comparator<A extends number, B extends number> = A extends B
? Comparison.Equal
: NegativeGreaterThan<A, B> extends true
? Comparison.Greater
: Comparison.Lower;
Solution by vangie #32346
enum Comparison {
Greater,
Equal,
Lower,
}
type CharComp<A, B, I extends 1[] = [], L = `${I["length"]}`> = A extends B
? Comparison.Equal
: L extends A
? Comparison.Lower
: L extends B
? Comparison.Greater
: CharComp<A, B, [...I, 1]>;
type NaturalComp<
A extends string,
B extends string,
C = Comparison.Equal,
> = A extends `${infer CA}${infer LA}`
? B extends `${infer CB}${infer LB}`
? NaturalComp<LA, LB, C extends Comparison.Equal ? CharComp<CA, CB> : C>
: Comparison.Greater
: B extends `${number}`
? Comparison.Lower
: C;
type Comparator<A extends number | bigint, B extends number | bigint> = `${A}` extends `-${infer X}`
? `${B}` extends `-${infer Y}`
? NaturalComp<Y, X>
: Comparison.Lower
: `${B}` extends `-${infer Y}`
? Comparison.Greater
: NaturalComp<`${A}`, `${B}`>;
Solution by alexandroppolus #32282
type num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
type MarkArr<N extends number, R extends unknown[] = []> = R['length'] extends N ? R : MarkArr<N, [0, ...R]>;
type Plus<A extends number, B extends number> = [...MarkArr<A>, ...MarkArr<B>]['length'];
type String2Number<S extends string, T extends any[] = []> = `${S}` extends `${T['length']}`
? T['length']
: String2Number<S, [0, ...T]>;
// 对比两个数字大小
type CompareNumber<A extends number, B extends number> = keyof MarkArr<A> extends keyof MarkArr<B>
? Comparison.Lower
: Comparison.Greater;
// 生成对照表
type NumberMap = {
[Key in `${num[number]}${num[number]}`]: Key extends `${infer A}${infer B}`
? CompareNumber<String2Number<A>, String2Number<B>>
: never;
};
// 对比长度
type ComparisonNumberArr<
S extends string[],
E extends string[],
P extends number = 0,
> =
// 长度是否相同
S['length'] extends E['length']
// 长度相同,则开始从P(默认是第一位0)位开始计算
? S[P] extends E[P]
// 如果相同,则P指针加1,继续计算
? ComparisonNumberArr<S, E, Plus<P, 1> & number>
// 类型收窄
: `${S[P]}${E[P]}` extends keyof NumberMap
? NumberMap[`${S[P]}${E[P]}`]
: never
// 长度不相同,则对比长度就可以知道大小了
: CompareNumber<S['length'], E['length']>;
// 数字转为字符串的数组
type TowNumberArray<
T extends string | number,
A extends string[] = [],
> = `${T}` extends `${infer S}${infer O}` ? TowNumberArray<O, [...A, S]> : A;
type Comparator<M extends number, N extends number> =
// 相等
M extends N
? Comparison.Equal
// 都是负数,则反转计算的结果
: `${M}${N}` extends `-${infer M1}-${infer N1}`
? ComparisonNumberArr<TowNumberArray<M1>, TowNumberArray<N1>> extends Comparison.Lower
? Comparison.Greater
: Comparison.Lower
// 第一个为负数
: `${M}${N}` extends `-${infer M1}${infer N1}`
? Comparison.Lower
// 第二个为负数
: `${M}${N}` extends `${infer M1}-${infer N1}`
? Comparison.Greater
// 都是正数
: `${M}${N}` extends `${infer M2}${infer N2}`
? ComparisonNumberArr<TowNumberArray<M>, TowNumberArray<N>>
: never;
Solution by jiangxd2016 #31573
// your answers
type MyEqual<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false
type IsFNumber<T extends string | number> = `${T}` extends `-${number}` ? true : false
type GetNumber<T extends string | number> = `${T}` extends `-${infer N}` ? N : T
type NTCompare<T extends string | number, N extends string | number> = IsFNumber<T> extends IsFNumber<N> ? never : IsFNumber<T> extends true ? Comparison.Lower : Comparison.Greater
type GetNumberArray<T extends string | number, R extends number[] = []> = `${R['length']}` extends `${T}` ? R : GetNumberArray<T, [...R, 0]>
type EasyCompare<A extends string | number, B extends string | number> =
GetNumberArray<GetNumber<A>> extends [...GetNumberArray<GetNumber<B>>, ...number[]]
? IsFNumber<A> extends true ? Comparison.Lower : Comparison.Greater
: IsFNumber<A> extends true ? Comparison.Greater : Comparison.Lower;
type EComparator<A extends string | number, B extends string | number> = NTCompare<A, B> extends never ? MyEqual<A, B> extends true ? Comparison.Equal : EasyCompare<A, B> : NTCompare<A, B>
type Comparator<A extends string | number, B extends string | number> = NTCompare<A, B> extends never ? MyEqual<A, B> extends true ? Comparison.Equal :
IsFNumber<A> extends true ? PEasyCompare<GetNumberPArray<B>, GetNumberPArray<A>> : PEasyCompare<GetNumberPArray<A>, GetNumberPArray<B>> : NTCompare<A, B>
type GetNumberPArray<T extends number | string> = `${T}` extends `${infer F}${infer Rest}` ? [F, ...GetNumberPArray<Rest>] : []
type PEasyCompare<A extends Array<string | number>, B extends Array<string | number>> = EComparator<A['length'], B['length']> extends Comparison.Equal
? PCompare<A, B>
: EComparator<A['length'], B['length']>
type GetFirst<T extends any[]> = T[0];
type GetRest<T extends any[]> = T extends [infer F, ...infer Rest] ? Rest : never;
type PCompare<A extends any[], B extends any[]> = EComparator<GetFirst<A>, GetFirst<B>> extends Comparison.Equal ?
A['length'] extends 1 ? Comparison.Equal : PCompare<GetRest<A>, GetRest<B>> : EComparator<GetFirst<A>, GetFirst<B>>
Solution by 437204933 #29922
enum Comparison {
Greater,
Equal,
Lower,
}
type JudgeMap = [
'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',
never
];
type JudgeOne<A extends string, B extends string> = B extends A
? Comparison.Equal
: B extends keyof JudgeMap
? A extends JudgeMap[B]
? Comparison.Greater
: Comparison.Lower
: Comparison.Equal;
type GetEmpty<A extends string> = A extends `${infer E}${infer R}`
? `.${GetEmpty<R>}`
: '';
type JudgeTemplate<A extends string, B extends string> = A extends B
? Comparison.Equal
: A extends `${infer L}${B}${infer R}`
? Comparison.Greater
: Comparison.Lower;
type JudgeLength<A extends string, B extends string> = JudgeTemplate<
GetEmpty<A>,
GetEmpty<B>
>;
type JudgeString<A extends string, B extends string> = JudgeLength<
A,
B
> extends Comparison.Equal
? A extends `${infer A1}${infer A2}`
? B extends `${infer B1}${infer B2}`
? JudgeOne<A1, B1> extends Comparison.Equal
? JudgeString<A2, B2>
: JudgeOne<A1, B1>
: Comparison.Equal
: Comparison.Equal
: JudgeLength<A, B>;
type Comparator<
A extends number,
B extends number
> = `${A}` extends `-${infer T1}`
? `${B}` extends `-${infer T2}`
? JudgeString<T2, T1>
: Comparison.Lower
: `${B}` extends `-${infer T2}`
? Comparison.Greater
: JudgeString<`${A}`, `${B}`>;
Solution by Royce-DaDaDa #29831
type IsNegative<N extends number | `${number}`> = `${N}` extends `-${number}` ? true : false;
type NumberToTuple<N extends number, Acc extends unknown[] = []> = Acc['length'] extends N
? Acc
: NumberToTuple<N, [...Acc, unknown]>;
enum Comparison {
Greater,
Equal,
Lower,
}
type Comparator<A extends number | `${number}`, B extends number | `${number}`> = A extends B
? Comparison.Equal
: [IsNegative<A>, IsNegative<B>] extends [true, false]
? Comparison.Lower
: [IsNegative<A>, IsNegative<B>] extends [false, true]
? Comparison.Greater
: [IsNegative<A>, IsNegative<B>] extends [true, true]
? [`${A}`, `${B}`] extends [`-${infer APositive}`, `-${infer BPositive}`]
? Comparator.ComparePositiveNumbers<Comparator.SplitNumber<BPositive>, Comparator.SplitNumber<APositive>>
: never
: Comparator.ComparePositiveNumbers<Comparator.SplitNumber<A>, Comparator.SplitNumber<B>>;
namespace Comparator {
export type ComparePositiveNumbers<
A extends number[],
B extends number[],
> = `${A['length']}` extends keyof B & `${number}`
? Comparison.Lower
: `${B['length']}` extends keyof A & `${number}`
? Comparison.Greater
: CompareEqualLengthNumbers<A, B>;
type CompareEqualLengthNumbers<A extends number[], B extends number[]> = [A, B] extends [
[infer A0 extends number, ...infer ARest extends number[]],
[infer B0 extends number, ...infer BRest extends number[]],
]
? CompareNumbers<A0, B0> extends Comparison.Equal
? CompareEqualLengthNumbers<ARest, BRest>
: CompareNumbers<A0, B0>
: Comparison.Equal;
type CompareNumbers<A extends number, B extends number> = A extends B
? Comparison.Equal
: `${A}` extends keyof NumberToTuple<B> & `${number}`
? Comparison.Lower
: Comparison.Greater;
export type SplitNumber<N extends number | string> =
`${N}` extends `${infer N0 extends number}${infer NRest extends string}`
? [N0, ...SplitNumber<NRest>]
: [];
}
Solution by BOCbMOU #27800
enum Comparison {
Greater,
Equal,
Lower,
}
type GreatConfig = {
"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': never,
}
type CompareDigit<
A extends string,
B extends string,
> =
A extends B?
Comparison.Equal:
A extends keyof GreatConfig?
B extends GreatConfig[A]?
Comparison.Lower:Comparison.Greater
:never
type CompareDigits<
A extends string,
B extends string,
> =
[A,B] extends [`${infer AF}${infer AR}`,`${infer BF}${infer BR}`]?
CompareDigit<AF,BF> extends infer CR?
CR extends Comparison.Equal?
CompareDigits<AR,BR>
:CR
:never
: Comparison.Equal
type CompareByLength<
A extends string,
B extends string,
> =
A extends `${infer AF}${infer AR}`?
B extends `${infer BF}${infer BR}`?
CompareByLength<AR,BR>:
Comparison.Greater
: B extends `${infer BF}${infer BR}`?
Comparison.Lower:Comparison.Equal
type CompareNonNegative<
A extends string,
B extends string,
ByLength extends Comparison = CompareByLength<A,B>
> =
ByLength extends Comparison.Equal?
CompareDigits<A,B>:
ByLength
type Comparator<
A extends number,
B extends number
> =
`${A}` extends `-${infer ABS_A}`?
`${B}` extends `-${infer ABS_B}`?
CompareNonNegative<ABS_B,ABS_A>
: Comparison.Lower
: `${B}` extends `-${infer ABS_B}`?
Comparison.Greater
: CompareNonNegative<`${A}`,`${B}`>
Solution by jiangshanmeta #27759
// Improved version
type CompareDigits<D1 extends string, D2 extends string> = D1 extends D2
? Comparison.Equal
: '9876543210' extends `${string}${D1}${string}${D2}${string}`
? Comparison.Greater
: Comparison.Lower;
type ComparePositiveIntegers<
A extends string,
B extends string,
TempResult extends Comparison = Comparison.Equal
> = A extends `${infer AF}${infer AR}`
? B extends `${infer BF}${infer BR}`
? TempResult extends Comparison.Equal
? ComparePositiveIntegers<AR, BR, CompareDigits<AF, BF>>
: ComparePositiveIntegers<AR, BR, TempResult>
: Comparison.Greater
: B extends `${infer _}${infer __}`
? Comparison.Lower
: TempResult;
type Comparator<
A extends number,
B extends number
> = `${A}` extends `-${infer AbsA}`
? `${B}` extends `-${infer AbsB}`
? ComparePositiveIntegers<AbsB, AbsA>
: Comparison.Lower
: `${B}` extends `-${number}`
? Comparison.Greater
: ComparePositiveIntegers<`${A}`, `${B}`>;
// My own version
type NumberToTuple<T, U extends 1[] = []> = U['length'] extends T
? U
: NumberToTuple<T, [...U, 1]>;
type GreaterOrEqual<
A extends number,
B extends number
> = NumberToTuple<A> extends [...NumberToTuple<B>, ...infer _] ? true : false;
type StringLength<
S extends string,
T extends 1[] = []
> = S extends `${infer _}${infer R}` ? StringLength<R, [...T, 1]> : T['length'];
type EqualLengthStringComparator<
A extends string,
B extends string
> = A extends `${infer A1 extends number}${infer AR}`
? B extends `${infer B1 extends number}${infer BR}`
? A1 extends B1
? EqualLengthStringComparator<AR, BR>
: GreaterOrEqual<A1, B1> extends true
? Comparison.Greater
: Comparison.Lower
: Comparison.Equal
: Comparison.Equal;
type PositivesComparator<
A extends number,
B extends number,
ALen extends number = StringLength<`${A}`>,
BLen extends number = StringLength<`${B}`>
> = ALen extends BLen
? EqualLengthStringComparator<`${A}`, `${B}`>
: GreaterOrEqual<ALen, BLen> extends true
? Comparison.Greater
: Comparison.Lower;
type Comparator<A extends number, B extends number> = A extends B
? Comparison.Equal
: `${A}` extends `-${infer T extends number}`
? `${B}` extends `-${infer U extends number}`
? PositivesComparator<U, T>
: Comparison.Lower
: `${B}` extends `-${number}`
? Comparison.Greater
: PositivesComparator<A, B>;
Solution by JohnLi1999 #26784
type Digit = ToArray<`0123456789`>;
type ToArray<T extends string | number | bigint> = `${T}` extends `${infer F}${infer R}` ? [F, ...ToArray<R>] : [];
type Length<T extends number | bigint | string> = ToArray<T>["length"];
/**最高位 */
type High<T extends string | number> = `${T}` extends `${infer F}${any}` ? F : ``;
/**更低位 */
type DigitLowerRest<T extends number | string> = `${T}` extends `${any}${infer R}` ? R : ``;
/**绝对值 */
type AbsString<T extends number | string | bigint> = `${T}` extends `-${infer N}` ? N : `${T}`;
/**是否负数 */
type IsNegative<T extends number | string | bigint> = `${T}` extends `-${any}` ? true : false;
/**比较单个位 */
type DigitComparator<T1 extends number | bigint | string, T2 extends number | bigint | string, IsNegative extends boolean = false, U extends string[] = Digit> =
(T1 extends T2 ?
Comparison.Equal :
(AbsString<T1> extends U[0] ?
(IsNegative extends false ? Comparison.Lower : Comparison.Greater) : //负值反转
(AbsString<T2> extends U[0] ?
(IsNegative extends false ? Comparison.Greater : Comparison.Lower) : //负值反转
(U extends [any, ...infer R extends string[]] ? DigitComparator<T1, T2, IsNegative, R> : false)
))
);
enum Comparison {
Greater,
Equal,
Lower,
}
type Comparator<A extends number | string, B extends number | string, _AIsNegative extends boolean = IsNegative<A>, _BIsNegative extends boolean = IsNegative<B>> =
[_AIsNegative & _BIsNegative] extends [never] ?
//一正一负
([0] extends [A & B] ? Comparison.Equal : //-0==0
_AIsNegative extends true ? Comparison.Lower : Comparison.Greater) //-X<Y
:
//正负相同
(Length<AbsString<A>> extends Length<AbsString<B>> ?
//位数相同,从高位开始比较
(`${A}${B}` extends `` ? Comparison.Equal : //直到全部位都相同 return 相同
(High<A> extends High<B> ?
Comparator<DigitLowerRest<A>, DigitLowerRest<B>, _AIsNegative, _BIsNegative> : //当前位相同,比较更低位
DigitComparator<High<A>, High<B>, _AIsNegative>) //当前位不同,retrun
)
:
//位数不同,比较位数大的
Comparator<Length<AbsString<A>>, Length<AbsString<B>>, _AIsNegative, _BIsNegative>);
Solution by E-uler #25523
enum Comparison {
Greater,
Equal,
Lower,
}
// -7 -> '7'
type AbsVal<T extends number> = `${T}` extends `-${infer A}` ? A : `${T}`
type IsNegative<T extends number> = `${T}` extends `-${infer A}` ? true : false
type NotAllZero<A extends number, B extends number> = AbsVal<A> extends '0'? AbsVal<B> extends '0'? false: true: true
type GreaterThan<A extends number,B extends number,C extends boolean,R1,R2,N extends number[] = []> =
IsNegative<B> extendsC
? R1
: `${AbsVal<A>}` extends `${N['length']}`
? R2
: `${AbsVal<B>}` extends `${N['length']}`
? R1
: GreaterThan<A, B, C, R1, R2, [...N, 0]>
type Comparator<A extends number, B extends number, N extends number[] = []> =
NotAllZero<A,B> extends false
? Comparison.Equal
: A extends B
? Comparison.Equal
: IsNegative<A> extends true
? GreaterThan<A, B, false, Comparison.Lower, Comparison.Greater, N>
: GreaterThan<A, B, true, Comparison.Greater, Comparison.Lower, N>
Solution by TKBnice #23777
// your answers
enum Comparison {
Greater,
Equal,
Lower,
}
// 判断是否是负数
type IsNegative<T extends number> = `${T}` extends `-${number}` ? true : false;
type NegativeToPositive<T extends number> =
`${T}` extends `-${infer R extends number}` ? R : never;
// 比较 0~9 这样的两个数大小, 判断 A > B 是否成立
type GreaterThan<
A extends number,
B extends number,
I extends 0[] = []
> = A extends B
? false
: I["length"] extends A
? I["length"] extends B
? false
: false
: I["length"] extends B
? true
: GreaterThan<A, B, [0, ...I]>;
// 获取最大值
type GetMax<A extends number, B extends number> = GreaterThan<
A,
B
> extends true
? A
: B;
// 获取字符串长度
type GetStringLength<
S extends string,
I extends 0[] = []
> = S extends `${string}${infer R}`
? GetStringLength<R, [0, ...I]>
: I["length"];
// 将字符串用0补全到指定位数
type FillZero<
S extends string,
N extends number
> = GetStringLength<S> extends N ? S : FillZero<`0${S}`, N>;
// 1. 两个都是正数的情况
// 2. 两个都是负数的情况
// 3. 一正一负的情况
// 传入的字符串会补到一样的长度 00000
type PositiveComparator<
A extends string,
B extends string,
isNeg extends boolean = false
> = A extends B
? Comparison.Equal
: A extends `${infer AF extends number}${infer AR}`
? B extends `${infer BF extends number}${infer BR}`
? AF extends BF
? PositiveComparator<AR, BR, isNeg>
: GreaterThan<AF, BF> extends true
? isNeg extends true
? Comparison.Lower
: Comparison.Greater
: isNeg extends true
? Comparison.Greater
: Comparison.Lower
: never
: never;
// 处理一正一负的情况
type NegAndPosComparator<
A extends number,
B extends number
> = `${A}` extends `-${number}` ? Comparison.Lower : Comparison.Greater;
type Comparator<
A extends number,
B extends number,
MaxLen extends number = GetMax<
GetStringLength<`${A}`>,
GetStringLength<`${B}`>
>
> = [IsNegative<A> | IsNegative<B>] extends [true]
? PositiveComparator<
FillZero<`${NegativeToPositive<A>}`, MaxLen>,
FillZero<`${NegativeToPositive<B>}`, MaxLen>,
true
>
: [IsNegative<A> | IsNegative<B>] extends [false]
? PositiveComparator<FillZero<`${A}`, MaxLen>, FillZero<`${B}`, MaxLen>>
: NegAndPosComparator<A, B>
Solution by acwink #22178
enum Comparison {
Greater,
Equal,
Lower,
}
// compare one bit chars of number without mark
type CompareOne<A extends string, B extends string> =
A extends B
? Comparison.Equal
: '0123456789' extends `${any}${A}${any}${B}${any}`
? Comparison.Lower
: Comparison.Greater
// reverse a string
type Reverse<S extends string> = S extends `${infer F}${infer Rest}` ? `${Reverse<Rest>}${F}` : ''
// compare positive numbers in string format
type ComparePositiveNumbers<A extends string, B extends string> =
Reverse<A> extends `${infer ALast}${infer ARest}`
? Reverse<B> extends `${infer BLast}${infer BRest}`
? ComparePositiveNumbers<Reverse<ARest>, Reverse<BRest>> extends Comparison.Equal
? CompareOne<ALast, BLast>
: ComparePositiveNumbers<Reverse<ARest>, Reverse<BRest>>
: Comparison.Greater
: B extends ''
? Comparison.Equal
: Comparison.Lower
// parse a number into [mark, value], where mark is + or -, and value is a string of number without mark
type ParseNumber<N extends number | string> =
`${N}` extends `-${infer V extends number}`
? ['-', `${V}`]
: ['+', `${N}`]
type Comparator<A extends number | string, B extends number | string> =
ParseNumber<A> extends [infer AM, infer AV extends string]
? ParseNumber<B> extends [infer BM, infer BV extends string]
? AM extends '-'
? BM extends '-'
? ComparePositiveNumbers<BV, AV> // - -
: Comparison.Lower // - +
: BM extends '-'
? Comparison.Greater // + -
: ComparePositiveNumbers<AV, BV> // + +
: never
: never
Solution by zhaoyao91 #22128
```ts
enum Comparison {
Greater,
Equal,
Lower,
}
type BigPositiveGreaterThan<
A extends string,
B extends string,
LA = LengthOfString<A>,
LB = LengthOfString<B>,
> = LA extends LB
? A extends `${infer AF extends number}${infer AR}`
? B extends `${infer BF extends number}${infer BR}`
? AF extends BF
? BigPositiveGreaterThan<AR, BR>
: GreaterThan<AF, BF>
: false
: never
: GreaterThan<LengthOfString<A>, LengthOfString<B>>
type PositiveComparator<
X extends number,
Y extends number,
> = BigPositiveGreaterThan<`${X}`, `${Y}`> extends true
? Comparison.Greater
: Comparison.Lower
type Comparator<A extends number, B extends number> = A extends B
? Comparison.Equal
: `${A}` extends `-${infer X extends number}`
? `${B}` extends `-${infer Y extends number}`
? PositiveComparator<Y, X>
: Comparison.Lower
: `${B}` extends `-${number}`
? Comparison.Greater
: PositiveComparator<A, B>
Solution by thanhhtse04588 #22013
enum Comparison {
Greater,
Equal,
Lower,
}
// # 4425
type _GreaterThanForPos<T extends number, U extends number, _Counter extends 0[] = []> =
_Counter['length'] extends T
? _Counter['length'] extends U
? Comparison.Equal
: Comparison.Lower
: _Counter['length'] extends U
? Comparison.Greater
: _GreaterThanForPos<T, U, [ ..._Counter, 0 ]>
// Limit version
// type Comparator<
// A extends number,
// B extends number,
// > = `${ A },${ B }` extends `-${ infer IA extends number },-${ infer IB extends number }`
// ? _GreaterThanForPos<IB, IA>
// : `${ A },${ B }` extends `${ number },-${ number }`
// ? Comparison.Greater
// : `${ A },${ B }` extends `-${ number },${ number }`
// ? Comparison.Lower
// : _GreaterThanForPos<A, B>
type _RemoveZeroes<T extends string> =
`${ T }` extends `${ infer A extends string }0${ infer B extends string }`
? B extends '' | '0' ? T : _RemoveZeroes<`${ A }${ B }`>
: T
type _CountStringLength<T extends string, _Counter extends 0[] = []> =
T extends `${ string }${ infer Rest }`
? _CountStringLength<Rest, [ ..._Counter, 0 ]>
: _Counter['length']
type _ComparatorNumberLengthForPos<
A extends number,
B extends number,
_A extends string = `${ A }` extends `${ infer I extends string }` ? I : never,
_B extends string = `${ B }` extends `${ infer I extends string }` ? I : never,
> = _GreaterThanForPos<_CountStringLength<_A>, _CountStringLength<_B>>
type _ComparatorEqualLengthForPos<
A extends number,
B extends number,
_A extends string = `${ A }` extends `${ infer I extends string }` ? _RemoveZeroes<I> : never,
_B extends string = `${ B }` extends `${ infer I extends string }` ? _RemoveZeroes<I> : never,
> = _A extends `${ infer FA extends number }${ infer RestA extends number }`
? _B extends `${ infer FB extends number }${ infer RestB extends number }`
? FA extends FB
? _ComparatorEqualLengthForPos<RestA, RestB>
: _GreaterThanForPos<FA, FB>
: never
: _GreaterThanForPos<A, B>
// No limit
type Comparator<A extends number, B extends number> =
`${ A },${ B }` extends `-${ infer IA extends number },-${ infer IB extends number }`
? _ComparatorNumberLengthForPos<IA, IB> extends Comparison.Equal
? _ComparatorEqualLengthForPos<IB, IA>
: _ComparatorNumberLengthForPos<IB, IA>
: `${ A },${ B }` extends `${ number },-${ number }`
? Comparison.Greater
: `${ A },${ B }` extends `-${ number },${ number }`
? Comparison.Lower
: _ComparatorNumberLengthForPos<A, B> extends Comparison.Equal
? _ComparatorEqualLengthForPos<A, B>
: _ComparatorNumberLengthForPos<A, B>
Solution by lvjiaxuan #21929
type IntADT = number | string | bigint;
type DigitLUT = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
type Digit = DigitLUT[number];
type Comparator<
A extends IntADT,
B extends IntADT,
IS_SIGN_SYMMETRIC extends boolean = SignSymmetry<A, B> extends -1 ? false : true,
RESULT extends Comparison = Equal<A, B> extends true ? Comparison.Equal
: IS_SIGN_SYMMETRIC extends true
? IsNonNegative<A> extends true
? UnsignedIntComparator<A, B> : UnsignedIntComparator<Absolute<B>, Absolute<A>>
: IsNonNegative<A> extends true
? Comparison.Greater : Comparison.Lower
> = RESULT;
type UnsignedIntComparator<
A extends IntADT,
B extends IntADT,
A_LENGTH extends number = IntLength<A>,
B_LENGTH extends number = IntLength<B>,
A_MSD extends Digit = MSD<A>,
B_MSD extends Digit = MSD<B>,
A_NEXT extends string | '' = DropMSD<A>,
B_NEXT extends string | '' = DropMSD<B>,
COMP extends Comparison = DigitComparator<A_MSD, B_MSD>,
RESULT extends Comparison = Equal<A_LENGTH, B_LENGTH> extends false
? UnsignedIntComparator<A_LENGTH, B_LENGTH>
: All<[IsDigit<A>, IsDigit<B>]> extends true
? COMP
: COMP extends Comparison.Equal
? UnsignedIntComparator<A_NEXT, B_NEXT>
: COMP
> = RESULT;
type DigitComparator<
A extends IntADT,
B extends IntADT,
PREV extends Digit[] = DigitLUT,
CURR extends IntADT = PREV[0],
IS_A extends boolean = Equal<`${A}`, `${CURR}`>,
IS_B extends boolean = Equal<`${B}`, `${CURR}`>,
NEXT extends Digit[] = Shift<PREV>,
RESULT extends Comparison = IS_A extends true
? IS_B extends true ? Comparison.Equal : Comparison.Lower
: IS_B extends true ? Comparison.Greater : DigitComparator<A, B, NEXT>
> = RESULT;
/** Helpers */
type IsDigit<N extends IntADT> =
`${N}` extends Digit ? true : false;
type IntLength<N extends IntADT, M extends Digit[] = []> =
`${N}` extends `${infer D extends Digit}${infer Rest}` ? IntLength<Rest, Push<M, D>> : M["length"];
/** @returns Digit */
type MSD<N extends IntADT> =
`${N}` extends `${infer H extends Digit}${string}` ? H : '0';
/** @returns string | '' */
type DropMSD<N extends IntADT> =
`${N}` extends `${infer H extends Digit}${infer Rest}` ? Rest : never;
type Signum<N extends IntADT> =
`${N}` extends '0' ? 0
: `${N}` extends `-${infer _}` ? -1 : 1;
type SignSymmetry<A extends IntADT, B extends IntADT> =
`${A}` extends `${B}` ? 0
: Any<[All<[IsNonNegative<A>, IsNonNegative<B>]>, All<[IsNegative<A>, IsNegative<B>]>]> extends true
? 1 : -1;
type IsNonNegative<N extends IntADT> =
IsNegative<N> extends false ? true : false;
type IsNegative<N extends IntADT> =
Signum<N> extends -1 ? true : false;
type Absolute<N extends IntADT> =
IsNegative<N> extends true
? `${N}` extends `-${infer R extends number}` ? R : N
: N;
/** Utilities */
type All<T extends boolean[]> =
T extends [infer B, ...infer Rest extends boolean[]]
? B extends true ? All<Rest> : false
: true;
type Shift<T extends any[], N extends number = 1> =
N extends 0 ? T
: T extends [infer _, ...infer Rest]
? Shift<Rest, Subtract<N, 1>>
: [];
(For reference, in case any part of the above is unclear.)
function Comparator(A, B) {
if (SignSymmetry(A, B) === 0) return Comparison.Equal
if (SignSymmetry(A, B) === 1) {
if (A >= 0) return UnsignedIntComparator(A, B)
else return InvertComparison(UnsignedIntComparator(Absolute(A), Absolute(B)))
}
if (SignSymmetry(A, B) === -1) {
if (A >= 0) return Comparison.Greater
else return Comparison.Lower
}
}
function UnsignedIntComparator(A, B) {
if (IntLength(A) === IntLength(B)) {
if (IntLength(A) === 1 && IntLength(B) === 1) return SingleDigitComparator(A, B)
for (const MSD_A of String(A)) {
for (const MSD_B of String(B)) {
if (MSD_A === MSD_B) return UnsignedIntComparator(String(A).slice(1), String(B).slice(1))
return SingleDigitComparator(MSD_A, MSD_B)
}
}
} else return UnsignedIntComparator(IntLength(A), IntLength(B))
}
function SingleDigitComparator(A, B, M = [0,1,2,3,4,5,6,7,8,9]) {
if (A === M[0]) {
if (B === M[0]) return Comparison.Equal
else return Comparison.Lower
} else {
if (B === M[0]) return Comparison.Greater
else return SingleDigitComparator(A, B, M.slice(1))
}
}
function SignSymmetry(A, B) {
if (A === B) return 0
if (A >= 0 && B >= 0 || A < 0 && B < 0) return +1
else return -1
}
IntLength
type correctly processes all of the following except for len22*
, which returns 21. Integer length of 17 seems to be the point where floats start to get rounded, and 22 is where automatic conversion to scientific notation takes place.type len1 = IntLength<0>
type len16 = IntLength<1234567891234567>
type len16_maxsafe = IntLength<9007199254740992>
type len21 = IntLength<123456789123456789123>
type len22* = IntLength<1234567891234567891234>
type len23_str = IntLength<'12345678912345678912345'>
type len26_str = IntLength<'abcdefghijklmnopqrstuvwxyz'>
const len16_maxsafe = `${9007199254740992}` as const // 9007199254740992
const len17 = `${12345678912345678}` as const // 12345678912345678
const len18_rounded = `${123456789123456789}` as const // 123456789123456780
const len21_rounded = `${123456789123456789123}` as const // 123456789123456800000
const len22_scientific = `${1234567891234567891234}` as const // "1.234567891234568e+21"
const len22-1 = `${1234567891234567891234}`.length // 21
type Comparator<A extends number | string, B extends number | string> =
number
type inputs of the same sign and length that have absolute values larger than Number.MAX_SAFE_INTEGER
will always result in a Comparison.Equal
due to rounding.Solution by MajorLift #21601
enum Comparison {
Greater,
Equal,
Lower,
}
type Build<
T extends number,
Result extends Array<never> = []
> = Result["length"] extends T ? Result : Build<T, [...Result, never]>;
type EGT<T extends number, B extends number> = Build<T> extends [
...Build<B>,
...infer C
]
? true
: false;
type InferNum<T extends number> = `${T}` extends `-${infer A extends number}`
? A
: T;
type Comparator_<A extends number, B extends number> = EGT<
InferNum<A>,
InferNum<B>
> extends true
? Comparison.Greater
: Comparison.Lower;
type Comparator<A extends number, B extends number> = A extends B
? Comparison.Equal
: [
`${A}` extends `-${infer A1 extends number}` ? true : false,
`${B}` extends `-${infer B1 extends number}` ? true : false
] extends [true, true]
? Comparator_<B, A>
: [
`${A}` extends `-${infer A1 extends number}` ? true : false,
`${B}` extends `${infer B1 extends number}` ? true : false
] extends [true, true]
? Comparison.Lower
: [
`${A}` extends `${infer A1 extends number}` ? true : false,
`${B}` extends `-${infer B1 extends number}` ? true : false
] extends [true, true]
? Comparison.Greater
: Comparator_<A,B>;
Solution by so11y #21394
type ComparatorPos<N1 extends number, N2 extends number, arr extends number[] = []> =
arr['length'] extends N1 ? (arr['length'] extends N2 ? Comparison.Equal : Comparison.Lower)
: arr['length'] extends N2 ? Comparison.Greater
: ComparatorPos<N1, N2, [...arr, arr['length']]>;
type Comparator<A extends number, B extends number> =
`${A}` extends `-${infer APos extends number}`
? `${B}` extends `-${infer BPos extends number}`
? ComparatorPos<BPos, APos>
: Comparison.Lower
: `${B}` extends `-${infer BPos extends number}`
? Comparison.Greater
: ComparatorPos<A, B>;
Solution by mdakram28 #20677
enum Comparison {
Greater,
Equal,
Lower,
}
type TenTimesArray<T extends unknown[]> = [
...T,
...T,
...T,
...T,
...T,
...T,
...T,
...T,
...T,
...T
]
type ArrayWithinTen<
T extends string | number,
R extends unknown[] = []
> = `${R['length']}` extends `${T}` ? R : ArrayWithinTen<T, [unknown, ...R]>
type ArrayWithLength<
T extends string | number,
R extends unknown[] = []
> = `${T}` extends `${infer A}${infer B}`
? ArrayWithLength<B, [...TenTimesArray<R>, ...ArrayWithinTen<A>]>
: R
type Pop<T extends unknown[]> = T extends [...infer A, unknown] ? A : T
type CompareNumber<
T extends string | number,
U extends string | number,
N extends boolean = false,
TA extends unknown[] = ArrayWithLength<T>,
UA extends unknown[] = ArrayWithLength<U>
> = TA['length'] extends 0
? UA['length'] extends 0
? Comparison.Equal
: N extends true
? Comparison.Greater
: Comparison.Lower
: UA['length'] extends 0
? N extends true
? Comparison.Lower
: Comparison.Greater
: CompareNumber<T, U, N, Pop<TA>, Pop<UA>>
type Comparator<
A extends number,
B extends number
> = `${A}` extends `-${infer C}`
? `${B}` extends `-${infer D}`
? CompareNumber<C, D, true>
: Comparison.Lower
: `${B}` extends `-${number}`
? Comparison.Greater
: CompareNumber<A, B>
Solution by theoolee #19847
enum Comparison {
Greater,
Equal,
Lower,
}
type Negative<A extends number> = `${A}` extends `-${infer N extends number}` ? N : false;
type Compare<A extends number, B extends number, C extends any[] = []> =
C['length'] extends A
? Comparison.Lower
: C['length'] extends B
? Comparison.Greater
: Compare<A, B, [...C, any]>;
type Comparator<A extends number, B extends number> =
A extends B
? Comparison.Equal
: [Negative<A>, Negative<B>] extends [infer AA, infer BB]
? [AA, BB] extends [false, false]
? Compare<A, B>
: [AA, BB] extends [false, number]
? Comparison.Greater
: [AA, BB] extends [number, false]
? Comparison.Lower
: Compare<BB & number, AA & number>
: never;
Solution by BulatDashiev #16983
enum Comparison {
Greater,
Equal,
Lower,
}
type IsEqual<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false
type IsMinus<A> = `${A & number}` extends `-${number}` ? true : false
type BuildArray<Len, Arr extends unknown[] = []> = Arr['length'] extends Len ? Arr : BuildArray<Len, [...Arr, unknown]>
type Compare<A extends number, B extends number> = BuildArray<A> extends [...BuildArray<B>, ...infer _] ? Comparison.Greater : Comparison.Lower
type Abs<T> = `${T & number}` extends `-${infer N extends number}` ? N : never
type Comparator<A extends number, B extends number> = IsEqual<A, B> extends true
? Comparison.Equal
: IsMinus<A> extends true
? IsMinus<B> extends false
? Comparison.Lower
: Compare<Abs<B>, Abs<A>>
: IsMinus<B> extends true
? Comparison.Greater
: Compare<A, B>
Solution by XkSuperCool #16936
type CheckInteger${T}
extends -${infer R}
? -1 : 1;
type StringToNumber<T extends string, R extends 0[] = []> = ${R['length']}
extends T ? R['length'] : StringToNumber<T, [...R, 0]>;
type ABS${T}
extends -${infer R}
? StringToNumber
type PositiveIntegerComparator<A extends number, B extends number, R extends 0[] = []> = A extends R['length'] ? B extends R['length'] ? Comparison.Equal : Comparison.Lower : B extends R['length'] ? Comparison.Greater : PositiveIntegerComparator<A, B, [...R, 0]>;
type Comparator<A extends number, B extends number> = CheckInteger extends 1 ? CheckInteger extends 1 ? PositiveIntegerComparator<A, B> : Comparison.Greater : CheckInteger extends -1 ? CheckInteger extends -1 ? PositiveIntegerComparator<ABS, ABS> : Comparison.Lower : CheckInteger extends 0 ? CheckInteger extends 0 ? Comparison.Equal : CheckInteger extends 1 ? Comparison.Lower : Comparison.Greater : never;
Solution by my5201314zwl #16804
// your answers
enum Comparison {
Greater,
Equal,
Lower,
}
type NumberToTuple<T extends number, Result extends 0[] = []> = Result['length'] extends T
? Result
: NumberToTuple<T, [0, ...Result]>
type MinusOne<T extends number, Result extends 0[] = NumberToTuple<T>> = Result extends [infer F, ...infer R]
? R['length']
: 0
type GT<T extends number, D extends number, E extends boolean = T extends D ? true : false> = E extends true ? false : T extends D
? true
: T extends 0
? false
: GT<MinusOne<T>, D, false>
type IsNegative<T extends number> = `${T}` extends `-${infer R extends number}`
? true
: false
type ABS<T extends number> = `${T}` extends `-${infer R extends number}`
? R
: T
type Comparator<A extends number, B extends number> = A extends B
? Comparison.Equal
: IsNegative<A> extends true
? IsNegative<B> extends true
? Comparator<ABS<B>, ABS<A>>
: Comparison.Lower
: IsNegative<B> extends true
? Comparison.Greater
: GT<A, B> extends true
? Comparison.Greater
: Comparison.Lower
Solution by humandetail #16616
// your answers
enum Comparison {
Greater,
Equal,
Lower,
} ;
type Dictionary<
E extends any = any > =
{
'0':[],
'1':[E],
'2':[E,E],
'3':[E,E,E],
'4':[E,E,E,E],
'5':[E,E,E,E,E],
'6':[E,E,E,E,E,E],
'7':[E,E,E,E,E,E,E],
'8':[E,E,E,E,E,E,E,E],
'9':[E,E,E,E,E,E,E,E,E],
} ;
type _10<
E extends any = any> = [E,E,E,E,E,E,E,E,E,E] ;
type Multyply<
A extends readonly any[],
B extends readonly any[]> =
A extends [infer R,...infer U]
? [...B,...Multyply<U,B>]
: [] ;
type ReverseString<
S extends string> =
S extends `${infer R extends string}${infer U extends string}`
? `${ReverseString<U>}${R}`
: '' ;
type ReverseStringToTuple<
S extends string,
E extends any = any> =
S extends `${infer R extends keyof Dictionary<E>}${infer U extends string}`
? [...Dictionary<E>[R],...Multyply<_10<E>,ReverseStringToTuple<U>>]
: [] ;
type Dif<
A extends number,
B extends number> =
`${A}` extends `-${infer R extends number}`
? `${B}` extends `-${infer U extends number}`
? ReverseStringToTuple<ReverseString<`${A}`>> extends
[...ReverseStringToTuple<ReverseString<`${B}`>>,...infer R extends readonly any[]]
? `-${R['length'] }` extends `${infer N extends number}`
? N
: never
: ReverseStringToTuple<ReverseString<`${B}`>> extends
[...ReverseStringToTuple<ReverseString<`${A}`>>,...infer R extends readonly any[]]
? R['length']
: never
: [...ReverseStringToTuple<ReverseString<`${A}`>>,...ReverseStringToTuple<ReverseString<`${B}`>>] extends
infer R extends readonly any[]
? `-${R['length']}` extends `${infer N extends number}`
? N
: never
: never
: `${B}` extends `-${infer U extends number}`
? [...ReverseStringToTuple<ReverseString<`${A}`>>,...ReverseStringToTuple<ReverseString<`${B}`>>] extends
infer R extends readonly any[]
? R['length']
: never
: ReverseStringToTuple<ReverseString<`${A}`>> extends
[...ReverseStringToTuple<ReverseString<`${B}`>>,...infer R extends readonly any[]]
? R['length']
: ReverseStringToTuple<ReverseString<`${B}`>> extends
[...ReverseStringToTuple<ReverseString<`${A}`>>,...infer R extends readonly any[]]
? `-${R['length'] }` extends `${infer N extends number}`
? N
: never
: never ;
type Lesser<
A extends number,
B extends number> =
`${Dif<A,B>}` extends `-${number}`
? true
: false ;
type Greater<
A extends number,
B extends number> =
`${Dif<B,A>}` extends `-${number}`
? true
: false ;
type Comparator<
A extends number,
B extends number> =
Greater<A,B> extends true
? Comparison.Greater
: Lesser<A,B> extends true
? Comparison.Lower
: Comparison.Equal ;
Solution by justBadProgrammer #16151
// your answers
enum Comparison {
Greater,
Equal,
Lower,
}
// A是否大于等于B
type Greater<A extends string, B extends string, Arr extends any[] = []> = `${Arr['length']}` extends B
? true
: `${Arr['length']}` extends A
? false
: Greater<A, B, [...Arr, 1]>
type Comparator<A extends number, B extends number> = A extends B ? Comparison.Equal
: `${A}` extends `-${infer PosA}`
? `${B}` extends `-${infer PosB}`
? Greater<PosA, PosB> extends true ? Comparison.Lower : Comparison.Greater
: Comparison.Lower
: `${B}` extends `-${infer PosB}` ? Comparison.Greater
: Greater<`${A}`, `${B}`> extends true ? Comparison.Greater : Comparison.Lower
Solution by fengchunqi #14621
enum Comparison {
Greater,
Equal,
Lower,
}
type Comparator_ToNumber<A extends string, T extends any[] = []> = `${T['length']}` extends `${A}` ? T['length'] : Comparator_ToNumber<A, [...T, 1]>
type Comparator_ABS<A extends number> = `${A}` extends `-${infer U}` ? Comparator_ToNumber<U> : A
// A 正 B 负
// A 负 B 正
// 比较两个正整数,数组从 0 开始,如果先匹配 A ,说明 B 大,先匹配 B,说明 A 大
type Comparator_CORE<A extends number, B extends number, T extends any[] = []> =
T['length'] extends A
? T['length'] extends B
? Comparison.Equal
: Comparison.Lower
: T['length'] extends B
? Comparison.Greater
: Comparator_CORE<A, B, [...T, 1]>
type Comparator<A extends number, B extends number> =
A extends Comparator_ABS<A>
? B extends Comparator_ABS<B>
? Comparator_CORE<A, B> // A 正 B 正
: Comparison.Greater
: B extends Comparator_ABS<B>
? Comparison.Lower
: Comparator_CORE<Comparator_ABS<B>, Comparator_ABS<A>> // A 负 B 负
Solution by WongYAQi #12490
type Get<T, K> = K extends keyof T ? T[K] : never;
type Reverse<S> = S extends `${infer First}${infer Rest}`
? `${Reverse<Rest>}${First}`
: '';
type ToUnion<S> = S extends `${infer First}${infer Rest}`
? First | ToUnion<Rest>
: never;
type Digits = '0123456789';
type GenerateGreater<D> = D extends `${infer First}${infer Rest}`
? { [key in First]: ToUnion<Rest> } & GenerateGreater<Rest>
: {};
type Greater = GenerateGreater<Digits>;
type InnerComparator<A, B> = A extends `${infer FirstA}${infer RestA}`
? B extends `${infer FirstB}${infer RestB}`
? FirstA extends FirstB
? InnerComparator<RestA, RestB>
: RestA extends RestB
? FirstA extends Get<Greater, FirstB>
? Comparison.Greater
: Comparison.Lower
: InnerComparator<RestA, RestB>
: Comparison.Greater
: Comparison.Equal;
enum Comparison {
Greater,
Equal,
Lower,
}
type Comparator<
A extends number,
B extends number,
SA = `${A}`,
SB = `${B}`,
> = SA extends `-${infer P}`
? SB extends `-${infer Q}`
? InnerComparator<Reverse<Q>, Reverse<P>>
: Comparison.Lower
: SB extends `-${string}`
? Comparison.Greater
: InnerComparator<Reverse<SA>, Reverse<SB>>;
Solution by ryo-mf-fjt #11801
enum Comparison {
Greater,
Equal,
Lower,
}
type Comparator<X extends number, Y extends number> = {'<': Comparison.Lower, '=': Comparison.Equal, '>': Comparison.Greater}[CompareNumbers<`${X}`, `${Y}`>]
// Type to compare two numeric types X and Y and determine their relational order as '<', '=', or '>'.
type CompareNumbers<X extends string, Y extends string>
= `${X}${Y}` extends `-${infer A}-${infer B}` ? CompareNumbers<B, A> // Handles comparison when both numbers are negative, invert the comparison order to compare their positive counterparts
: X extends `-${any}` ? '<' // If X is negative and Y is not Y is greater
: Y extends `-${any}` ? '>' // If Y is negative and X is not X is greater
: `${X} ${Y}` extends `${infer A}e+${infer E} ${infer B}e+${infer F}` ? CompareInteger<E, F> extends '=' ? CompareNumbers<A, B> : CompareInteger<E, F>
: X extends `${any}e+${any}` ? '>'
: Y extends `${any}e+${any}` ? '<'
: `${X} ${Y}` extends `${infer A}e-${infer E} ${infer B}e-${infer F}` ? CompareInteger<F, E> extends '=' ? CompareNumbers<A, B> : CompareInteger<F, E>
: X extends `${any}e-${any}` ? '<'
: Y extends `${any}e-${any}` ? '>'
: `${X} ${Y}` extends `${infer A}.${infer C} ${infer B}.${infer D}` ? CompareInteger<A, B> extends '=' ? CompareFractional<C, D> : CompareInteger<A, B>
: X extends `${infer A}.${any}` ? CompareInteger<A, Y> extends '=' ? '>' : CompareInteger<A, Y>
: Y extends `${infer B}.${any}` ? CompareInteger<X, B> extends '=' ? '<' : CompareInteger<X, B>
: CompareInteger<X, Y>
// Recursive type to compare integer strings and determine their order.
type CompareInteger<X extends string, Y extends string, PreviousComparison extends '<' | '=' | '>' = '='>
= X extends Y ? PreviousComparison // If both strings are equal, return the previous comparison result
: `${X} ${Y}` extends `${infer A}${infer C} ${infer B}${infer D}`
? CompareInteger<C, D,
PreviousComparison extends '<' | '>' ? PreviousComparison // If difference has been found, Carry forward the first difference
: A extends B ? '=' // If current digits are the same, skip to next
: '0123456789' extends `${any}${A}${any}${B}${any}` ? '<' : '>'> // Compare digits lexicographically
: X extends '' ? '<' : '>' // longer is greater
type CompareFractional<X extends string, Y extends string>
= `${X} ${Y}` extends `${infer A}${infer C} ${infer B}${infer D}`
? A extends B ? CompareFractional<C, D> // If current digits are the same, skip to next
: '0123456789' extends `${any}${A}${any}${B}${any}` ? '<' : '>' // Compare digits lexicographically
: X extends '' ? '<' : '>' // longer is greater
Solution by teamchong #11540
type Comparator<A extends number | string, B extends number | string>
= `${A}` extends `-${infer AbsA}`
? `${B}` extends `-${infer AbsB}`
? ComparePositives<AbsB, AbsA>
: Comparison.Lower
: `${B}` extends `-${number}`
? Comparison.Greater
: ComparePositives<`${A}`, `${B}`>
// Compares two positive long numbers
type ComparePositives<A extends string, B extends string, ByLength = CompareByLength<A, B>>
= ByLength extends Comparison.Equal
? CompareByDigits<A, B>
: ByLength
// Compares two strings by length
type CompareByLength<A extends string, B extends string>
= A extends `${infer AF}${infer AR}`
? B extends `${infer BF}${infer BR}`
? CompareByLength<AR, BR>
: Comparison.Greater
: B extends `${infer BF}${infer BR}`
? Comparison.Lower
: Comparison.Equal
// Compares two positive long numbers of the same length
type CompareByDigits<A extends string, B extends string>
= `${A}|${B}` extends `${infer AF}${infer AR}|${infer BF}${infer BR}`
? CompareDigits<AF, BF> extends Comparison.Equal
? CompareByDigits<AR, BR>
: CompareDigits<AF, BF>
: Comparison.Equal
// Compares two digits
type CompareDigits<A extends string, B extends string>
= A extends B
? Comparison.Equal
: '0123456789' extends `${string}${A}${string}${B}${string}`
? Comparison.Lower
: Comparison.Greater
Examples:
// CompareByLength
CompareByLength<"1234", "567"> // Greater
CompareByLength<"123", "4567"> // Lower
CompareByLength<"123", "456"> // Equal
// CompareByDigits
CompareByDigits<"1234", "1224"> // Greater
CompareByDigits<"1234", "1244"> // Lower
CompareByDigits<"1234", "1234"> // Equal
// CompareDigits
CompareDigits<"5", "3"> // Greater
CompareDigits<"5", "7"> // Lower
CompareDigits<"5", "5"> // Equal
Extra tests:
Expect<Equal<Comparator<1234567891012345, 1234567891012345>, Comparison.Equal>>
Expect<Equal<Comparator<1234567891012345, 1234567891012346>, Comparison.Lower>>
Expect<Equal<Comparator<1234567891012345, 1234567891011234>, Comparison.Greater>>
// use strings for numbers greater than Number.MAX_SAFE_INTEGER (9007199254740991)
Expect<Equal<Comparator<'1234567890123456789', '1234567890123456790'>, Comparison.Lower>>,
Solution by Alexsey #11444