Last active
October 16, 2020 10:14
-
-
Save shicks/0a505c589c6a5c2755ba75e7f4324eb0 to your computer and use it in GitHub Desktop.
Parsing integers in TypeScript's type system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type NumCat<X, Y> = X extends any[] ? Y extends any[] ? [...X, ...X, ...X, ...X, ...X, ...X, ...X, ...X, ...X, ...X, ...Y] : never : never; | |
type OneDigit = { | |
'0': [], '1': [any], '2': [any, any], '3': [any, any, any], | |
'4': [any, any, any, any], '5': [any, any, any, any, any], | |
'6': [any, any, any, any, any, any], '7': [any, any, any, any, any, any, any], | |
'8': [any, any, any, any, any, any, any, any], | |
'9': [any, any, any, any, any, any, any, any, any], | |
}; | |
type Digit<S> = S extends keyof OneDigit ? OneDigit[S] : never; | |
type Len<X> = X extends any[] ? X['length'] : never; | |
type Chars<X extends string> = X extends `${infer A}${infer B}` ? [A, ...Chars<B>] : []; | |
type ListStr<X extends any[]> = | |
X extends [any, ...any] ? X extends [...infer tens, infer ones] ? NumCat<ListStr<tens>, Digit<ones>> : never : []; | |
type Num<X extends string> = Len<ListStr<Chars<X>>>; | |
type Anys<X> = X extends [any, ...infer U] ? [any, ...Anys<[...U]>] : []; | |
type _Cmp<X, Y> = X extends [...Anys<Y>, ...any[]] ? Y extends [...Anys<X>, ...any[]] ? _Cmp1<X, Y> : 'gt' : 'lt'; | |
type _Cmp1<X, Y> = X extends [] ? 'eq' : X extends [infer X1, ...infer X2] ? Y extends [infer Y1, ...infer Y2] ? _Cmp2<Digit<X1>, Digit<Y1>, X2, Y2> : never : never; | |
type _Cmp2<X1 extends any[], Y1 extends any[], X2, Y2> = X1 extends [...Y1, ...any[]] ? Y1 extends [...X1, ...any[]] ? _Cmp1<X2, Y2> : 'gt' : 'lt'; | |
type Cmp<X extends number, Y extends number> = _Cmp<Chars<`${X}`>, Chars<`${Y}`>>; | |
type Tail<L> = L extends [any, ...infer U] ? U : {tail: L}; | |
type List<N extends number> = N extends 0 ? [] : _List<N, [[any]]>; | |
type _List<N extends number, L extends any[][]> = _List1<N, L, Cmp<N, L[0]['length']>>; | |
type _List1<N extends number, L extends any[][], C> = C extends 'eq' ? L[0] : C extends 'lt' ? _List2<N, Tail<L>, []> : _List<N, [[...L[0], ...L[0]], ...L]>; | |
type _List2<N extends number, L, O extends any[]> = L extends any[][] ? _List3<N, L, O> : {N: N, L: L, O: O}; | |
type _List3<N extends number, L extends any[][], O extends any[]> = _List4<N, L, O, [...L[0], ...O]>; | |
type _List4<N extends number, L extends any[][], O1 extends any[], O2 extends any[]> = | |
_List5<N, L, O1, O2, Cmp<N, O2['length']>>; | |
type _List5<N extends number, L extends any[][], O1 extends any[], O2 extends any[], C> = | |
C extends 'eq' ? O2 : C extends 'gt' ? _List2<N, Tail<L>, O2> : _List2<N, Tail<L>, O1> | |
type Add<X extends number, Y extends number> = Len<[...List<X>, ...List<Y>]>; | |
type Mul<X extends number, Y extends number> = Len<_Mul<List<X>, List<Y>>>; | |
type _Mul<X extends any[], Y extends any[]> = X extends [any, ...infer U] ? [...Y, ..._Mul<U, Y>] : []; | |
// Usage: | |
type five = Num<'5'>; | |
type twelveHundred = Num<'1200'>; | |
type sum = Add<123, 434>; | |
type product = Mul<23, 53>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Playground link