const charToIntMap = {
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9
} as const;
type ArrayOfN<N extends number, K extends any[] = []> = N extends K['length'] ? K : ArrayOfN<N, [...K, any]>;
type DigitChar = keyof typeof charToIntMap;
type Digit = typeof charToIntMap[DigitChar];
type DigitCharToInt<K extends DigitChar> = typeof charToIntMap[K];
type Add<A extends number, B extends number> = [...ArrayOfN<A>, ...ArrayOfN<B>]['length'];
type CharAdd<A extends DigitChar, B extends DigitChar> = Add<DigitCharToInt<A>, DigitCharToInt<B>>;
type LastDigitOfCharAdd<A extends DigitChar, B extends DigitChar> = CharAdd<A, B> extends number ? LastChar<ToString<CharAdd<A, B>>> : never;
type ToString<N extends number | bigint> = `${N}`;
type LastChar<K extends string, F extends string = ''> = K extends `${infer L}${infer R}` ? LastChar<R, L> : F;
type LastCharToInt<K extends string> = LastChar<K> extends DigitChar ? DigitCharToInt<LastChar<K>> : never;
type PopLastChar<K extends string, F extends string = ''> = K extends `${infer L}${infer R}` ?
R extends '' ? F : PopLastChar<R, `${F}${L}`> : '';
type CalcLastDigitSum<A extends string, B extends string, C extends number> =
LastChar<A> extends DigitChar ? LastChar<B> extends DigitChar ?
Add<LastCharToInt<A>, LastCharToInt<B>> extends number ?
Add<C, Add<LastCharToInt<A>, LastCharToInt<B>>> :
never : never : never;
type CalcLastDigitSumToChar<A extends string, B extends string, C extends number> =
CalcLastDigitSum<A, B, C> extends number ? LastChar<ToString<CalcLastDigitSum<A, B, C>>> : never;
type Carry<A extends string, B extends string, C extends number> =
CalcLastDigitSum<A, B, C> extends Digit ? 0 : 1;
type Sum<A extends number | bigint | string, B extends number | bigint | string, R extends string = '', C extends number = 0> =
A extends number | bigint ? Sum<ToString<A>, B, R, C> :
B extends number | bigint ? Sum<A, ToString<B>, R, C> :
A extends string ? B extends string ?
A extends '' ? B extends '' ? C extends 1 ? `1${R}` : R : Sum<'0', B, R, C> :
B extends '' ? Sum<A, '0', R, C> :
Sum<PopLastChar<A>, PopLastChar<B>, `${CalcLastDigitSumToChar<A, B, C>}${R}`, Carry<A, B, C>> : never : never;
type T0 = Sum<2, 3> // '5'
type T1 = Sum<'13', '21'> // '34'
type T2 = Sum<'328', 7> // '335'
type T3 = Sum<1_000_000_000_000n, '123'> // '1000000000123'
Solution by nahcikuy #34962
type MapAdd = [
[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9]],
[[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [1, 0]],
[[0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [1, 0], [1, 1]],
[[0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [1, 0], [1, 1], [1, 2]],
[[0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [1, 0], [1, 1], [1, 2], [1, 3]],
[[0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4]],
[[0, 6], [0, 7], [0, 8], [0, 9], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5]],
[[0, 7], [0, 8], [0, 9], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6]],
[[0, 8], [0, 9], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7]],
[[0, 9], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7], [1, 8]]
];
type Add<M extends number[], N extends number[]> = M extends [
...infer MRest extends number[],
infer MLast extends number
]
? N extends [...infer NRest extends number[], infer NLast extends number]
? MapAdd[MLast][NLast] extends [infer TensPlace1 extends number, infer OnesPlace1]
? [...Add<MRest, [TensPlace1]>, OnesPlace1] extends [...infer Rest2 extends number[], infer OnesPlace2]
? [...Add<Rest2, NRest>, OnesPlace2]
: never
: never
: M
: N;
type StringToNumber<S extends string> = S extends `${infer M extends number}` ? M : never;
type StringToTuple<N extends string> = `${N}` extends `${infer A}${infer B}`
? [StringToNumber<A>, ...StringToTuple<B>]
: [];
type Join<M extends number[]> = M extends [infer First extends number, ...infer Rest extends number[]]
? `${First}${Join<Rest>}`
: "";
type Format<M extends number[]> = M extends [0, ...infer Rest extends number[]]
? Format<Rest>
: M extends []
? Join<[0]>
: Join<M>;
type Sum<A extends string | number | bigint, B extends string | number | bigint> = Format<
Add<StringToTuple<`${A}`>, StringToTuple<`${B}`>>
>;
Solution by yukicountry #34532
type ReverseString<S extends string> = S extends `${infer Head}${infer Tail}`
? `${ReverseString<Tail>}${Head}`
: '';
type SumDigits<
A1 extends number,
A2 extends number,
Acc extends unknown[][] = [[], []]
> = Acc[0]['length'] extends A1
? Acc[1]['length'] extends A2
? [...Acc[0], ...Acc[1]]['length']
: SumDigits<A1, A2, [Acc[0], [unknown, ...Acc[1]]]>
: SumDigits<A1, A2, [[unknown, ...Acc[0]], Acc[1]]>;
type SumHelper<A extends string, B extends string, Rest extends number = 0> =
A extends `${infer HeadA extends number}${infer TailA}`
? B extends `${infer HeadB extends number}${infer TailB}`
? `${SumDigits<SumDigits<HeadA, HeadB>, Rest>}` extends `${infer SumRest extends number}${infer Result extends number}`
? `${Result}${SumHelper<TailA, TailB, SumRest>}`
: `${SumDigits<SumDigits<HeadA, HeadB>, Rest>}${SumHelper<TailA, TailB, 0>}`
: Rest extends 0 ? A : SumHelper<A, '0', Rest>
: Rest extends 0 ? B : SumHelper<B, '0', Rest>;
type Sum<A extends string | number | bigint, B extends string | number | bigint> =
ReverseString<SumHelper<ReverseString<`${A}`>, ReverseString<`${B}`>>>;
Solution by user1808 #32673
思路:
AddReturn
,结果必然是小于 20
,因此继续拆分结果的个位数 V
去和前面的结果 Acc
拼接 ${V}${Acc}
,然后把进位 Carry
传到下一位的相加运算中A
还没遍历完,先判断还有没有进位 1
,有的话让 A
和 1
去相加,反之拼接返回 ${Reverse<A>}${Acc}
(注意这里原来 A 进来是翻转的,所以这里要再翻转一次,才能得到正确的结果),例如:A: '1234', B: '1', Acc: ''
进行翻转
A: '4321', B: '1', Acc: ''
第一位相加
A: '321', B: '', Acc: '5'
B没有内容了,A翻转与Acc拼接
A: '123', Acc: '5' => '1235'
type NArray<S extends string, N extends number = StringToNumber<S>, Acc extends any[] = []> =
N extends Acc['length'] ? Acc : NArray<S, N, [...Acc, 0]>
type StringToNumber<S extends string> = S extends `${infer N extends number}` ? N : 0
// 3 number add
type Add<A extends string, B extends string, Carry extends string> = [...NArray<A>, ...NArray<B>, ...NArray<Carry>]['length']
// 3 digit number add , get { singleDigit, carry }
type AddReturn<A extends string, B extends string, Carry extends string, R = Add<A, B, Carry>> =
R extends number ?
`${R}` extends `1${infer N extends number}`
? {
singleDigit: N
carry: '1'
}
: {
singleDigit: R
carry: '0'
}
: never
type Reverse<S extends string, R extends string = ''> =
S extends `${infer F}${infer Rest}`
? Reverse<Rest, `${F}${R}`>
: R
type _Sum<A extends string, B extends string, Acc extends string = '', Carry extends '0' | '1' = '0' > =
A extends `${infer HA extends string}${infer TA}`
? B extends `${infer HB extends string}${infer TB}`
? AddReturn<HA, HB, Carry> extends {
singleDigit: infer V extends number
carry: infer N extends '0' | '1'
}
? _Sum<TA, TB, `${V}${Acc}`, N> // Acc behind V,
: never //
: Carry extends '1' ? _Sum<A, '1', Acc, '0'> : `${Reverse<A>}${Acc}` // reverse A
: Carry extends '1' ? _Sum<B, '1', Acc, '0'> : `${Reverse<B>}${Acc}` // revere B
type Sum<A extends string | number | bigint, B extends string | number | bigint> = _Sum<Reverse<`${A}`>, Reverse<`${B}`>>
Solution by action-hong #32508
type Num<A extends number, P extends 1[] = []> = A extends P['length'] ? P : Num<A, [1, ...P]>
type PlusNums<A extends number, B extends number> = Num<A> extends [...infer P] ? Num<B> extends [...infer Q] ? [...P, ...Q]['length'] : never : never
type GreaterThanEqual<A extends number , B extends number, P = Num<A>, Q = Num<B>> = P extends 1[] ? Q extends 1[] ? Q['length'] extends 0 ? true:
P['length'] extends 0 ? false :
P extends [1, ...infer R] ?
Q extends [1, ...infer S] ?
GreaterThanEqual<A, B, R, S>
: never
: never
: never
: never
type StringNum<A extends string | number | bigint> = A extends string ? A : `${A}`
type StringSize<A extends string, P extends 1[] = []> = A extends `${number}${infer B}` ? StringSize<B, [1, ...P]> : P['length']
type Reverse<A extends string> = A extends `${infer B}${infer C}` ? `${Reverse<C>}${B}` : ""
type ArrayJoin<A extends unknown[], P extends string = ""> = A['length'] extends 0 ? P : A extends [infer K extends number, ...infer B] ? ArrayJoin<B, `${P}${K}`> : never
type AppendZeros<A extends string, Count extends number, P extends 0[] = []> = P['length'] extends Count ? `${A}${ArrayJoin<P>}` : AppendZeros<A, Count, [0, ...P]>
type ReverseSum<A extends string, B extends string, Result extends string = "" , PlusOne = false> =
A extends `${infer AFirst extends number}${infer ARest}` ?
B extends `${infer BFirst extends number}${infer BRest}` ?
PlusNums<PlusNums<AFirst, BFirst>, PlusOne extends true ? 1 : 0> extends (infer U extends number)
? `${U}` extends `${infer UFirst extends number}${infer ULast extends number}`
? ARest extends "" ? `${Result}${ULast}${UFirst}` :ReverseSum<ARest, BRest, `${Result}${ULast}`, true>
: ReverseSum<ARest, BRest, `${Result}${U}`, false>
: never
: Result
: Result
type MakeSameOrder<A extends string, B extends string> =
StringSize<A> extends StringSize<B> ? [A, B] :
GreaterThanEqual<StringSize<A>, StringSize<B>> extends true ?
MakeSameOrder<A, AppendZeros<B, 1>> :
MakeSameOrder<AppendZeros<A,1>, B>
type Sum<A extends string | number | bigint, B extends string | number | bigint> = MakeSameOrder<Reverse<`${A}`>, Reverse<`${B}`>> extends [infer U extends string, infer R extends string] ?
Reverse<ReverseSum<U, R>>
: never
Solution by john-cremit #32491
type ReverseString<S extends string> = S extends `${infer First}${infer Rest}`
? `${ReverseString<Rest>}${First}`
: "";
type Tuple<T, C extends 0[] = []> = C["length"] extends T
? C
: Tuple<T, [...C, 0]>;
type SimpleAdd<A extends number, B extends number, Carry extends number = 0> = [
...Tuple<A>,
...Tuple<B>,
...Tuple<Carry>
]["length"];
type SumReversedString<
A extends string,
B extends string,
Carry extends number = 0
> = A extends `${infer FirstA extends number}${infer RestA}`
? B extends `${infer FirstB extends number}${infer RestB}`
? `${SimpleAdd<FirstA, FirstB, Carry> &
number}` extends `${infer NewCarry extends number}${infer Sum extends number}`
? `${Sum}${SumReversedString<RestA, RestB, NewCarry>}`
: `${SimpleAdd<FirstA, FirstB, Carry> & number}${SumReversedString<
RestA,
RestB,
0
>}`
: SumReversedString<A, `${Carry}`>
: B extends `${number}${string}`
? SumReversedString<`${Carry}`, B>
: Carry extends 0
? ""
: `${Carry}`;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = ReverseString<
SumReversedString<ReverseString<`${A}`>, ReverseString<`${B}`>>
>;
Solution by vangie #32352
type StringNumberToArray<S extends string> = S extends `${infer S0 extends number}${infer SRest}`
? [S0, ...StringNumberToArray<SRest>]
: [];
type NumberToArray<N extends number, A extends never[] = []> = A['length'] extends N
? A
: NumberToArray<N, [...A, never]>;
type Sum<
A extends `${number}` | number | bigint,
B extends `${number}` | number | bigint,
> = Sum.SumNumsAsArray<StringNumberToArray<`${A}`>, StringNumberToArray<`${B}`>, '', false>;
namespace Sum {
export type SumNumsAsArray<
A extends number[],
B extends number[],
Result extends string,
Leading extends boolean,
> = [A, B] extends [
[...infer ABody extends number[], infer ALast extends number],
[...infer BBody extends number[], infer BLast extends number],
]
? [
...NumberToArray<ALast>,
...NumberToArray<BLast>,
...(Leading extends true ? [never] : []),
]['length'] extends infer AB extends number
? `${AB}` extends `1${infer ABResult extends number}`
? SumNumsAsArray<ABody, BBody, `${ABResult}${Result}`, true>
: SumNumsAsArray<ABody, BBody, `${AB}${Result}`, false>
: never
: Leading extends true
? SumNumsAsArray<[...A, ...B], [1], Result, false>
: `${Join<[...A, ...B]>}${Result}`;
type Join<N extends number[]> = N extends [
infer N0 extends number,
...infer NRest extends number[],
]
? `${N0}${Join<NRest>}`
: '';
}
Solution by BOCbMOU #32006
// The idea behind this sum function is to work like a full-adder, except on a base-10 system.
// If that seems complicated, it's literally how you learned to sum longer numbers in grade school.
// Digits are summed in pairs, with a 'carry' flag in case the computation overflows
// ,,
// 2753
// + 102158
// --------
// 104901 (god I hope I didn't mess this up, or I'm going to be so embarrassed)
//
// The base case is when both numbers are exhausted of their digits, when the sum is finally returned
//
// Special cases:
// - 1 is appended to the Acc if the computation is done and the carry flag is still set
// - 0 is returned in case the Acc is still an empty string (i.e. when the computation is Sum<0, 0>)
//
// The code may seem dense at first glance, but most of it is just boilerplate pattern-matching
type Sum<A extends string | number | bigint, B extends string | number | bigint, C extends 1 | 0 = 0, Acc extends string = ''> =
[...Unsnoc<A>, ...Unsnoc<B>] extends ['', 0, '', 0]
? `${C extends 1 ? 1 : ''}${Acc extends '' ? 0 : Acc}` :
[...Unsnoc<A>, ...Unsnoc<B>] extends [infer InitA extends string, infer DigitA extends number, infer InitB extends string, infer DigitB extends number]
? Unsnoc<Add<DigitA, DigitB, C>> extends [infer C2, infer Rem extends number]
? Sum<InitA, InitB, C2 extends '1' ? 1 : 0, `${Rem}${Acc}`>
: never : never;
// Takes in a num(like), and returns the `init` and last digit of that number as a cons pair
// i.e. Unsnoc<123> = ['12', 3] (N.B. note that the former is a string)
type Unsnoc<N extends string | number | bigint> =
`${N}` extends `${infer Init extends string}${0|1|2|3|4|5|6|7|8|9}` // Unfortunately `${infer Init}${infer Last extends 0|1|2|3|4|5|6|7|8|9}` doesn't work
? `${N}` extends `${Init}${infer Last extends number}`
? [Init, Last] : never
: ['', 0];
// Adds an 'A' and 'B' together, also taking in the 'Carry' flag from the previous computation
type Add<A extends number, B extends number, C extends 1 | 0> =
[...Peano<A>, ...Peano<B>, ...Peano<C>] extends { length: infer L extends number } ? L : never;
type Peano<L extends number, T extends any[] = []> =
T['length'] extends L ? T : Peano<L, [...T, any]>;
Solution by toptobes #31684
type ToArray<T extends number, Arr extends any[] = []> = Arr['length'] extends T ? Arr : ToArray<T, [...Arr, any]>;
type Add<A extends number, B extends number> = [...ToArray<A>, ...ToArray<B>]['length'];
type ToNumber<T extends string> = T extends `${infer N extends number}` ? N : 0;
type ToString<T extends number | string> = T extends number ? `${T}` : T;
type parseNumber<T extends string, R extends string = ''> = T extends `${infer A extends number}${infer B}`
? parseNumber<B, `${R}${A}`>
: T extends `${any}${infer B}`
? parseNumber<B, R>
: R;
type ReserveString<T extends string> = T extends `${infer A}${infer B}` ? `${ReserveString<B>}${A}` : T;
type ReserveArray<T extends any[]> = T extends [infer A, ...infer B extends any[]] ? [...ReserveArray<B>, A] : [];
type Split<T extends string, S extends string = ''> = T extends `${infer A}${S}${infer B}` ? [A, ...Split<B, S>] : [T];
type Join<T extends string[], S extends string = ''> = T extends [infer A extends string, ...infer B extends any[]]
? B['length'] extends 0
? A
: `${A}${S}${Join<B, S>}`
: '';
/** 数组之和 */
type _Sum<
A extends string[],
B extends string[],
IA extends any[] = [],
IB extends any[] = [],
R extends string[] = [],
> = A['length'] extends IA['length']
? B['length'] extends IB['length']
? R
: _Sum<A, B, IA, [...IB, any], [...R, B[IB['length']]]>
: B['length'] extends IB['length']
? _Sum<A, B, [...IA, any], IB, [...R, A[IA['length']]]>
: _Sum<
A,
B,
[...IA, any],
[...IB, any],
[
...R,
`${Add<ToNumber<A[IA['length']]>, ToNumber<B[IB['length']]>> extends number
? Add<ToNumber<A[IA['length']]>, ToNumber<B[IB['length']]>>
: 0}`,
]
>;
/** 进位 */
type carry<T extends string[], R extends string[] = [], S extends 0 | 1 = 0> = T extends [
infer A extends string,
...infer B extends string[],
]
? A extends `${number}${infer D extends number}`
? carry<B, [...R, `${Add<S, D> extends number ? Add<S, D> : 0}`], 1>
: carry<B, [...R, `${Add<S, ToNumber<A>> extends number ? Add<S, ToNumber<A>> : 0}`], 0>
: R;
type removeZero<T extends string> = T extends `0${infer A}` ? removeZero<A> : T;
type Sum<A extends number | string, B extends number | string> = removeZero<
Join<
ReserveArray<
carry<
_Sum<
Split<ReserveString<parseNumber<ToString<A>>>>,
Split<ReserveString<parseNumber<ToString<B>>>>
> extends string[]
? _Sum<
Split<ReserveString<parseNumber<ToString<A>>>>,
Split<ReserveString<parseNumber<ToString<B>>>>
>
: []
>
>
>
>;
Solution by zhengybo #31450
// sum the lengths of three arrays
type ArrToSum<T extends any[], U extends any[], S extends any[]> = `${[
...T,
...U,
...S
]["length"]}`;
// convert a number string (e.g., "1", "21") to an array with the corresponding length
type StrToArr<T extends string, U extends never[] = []> = T extends ""
? []
: `${U["length"]}` extends `${T}`
? U
: StrToArr<T, [...U, never]>;
// sum single digits (e.g., A = "1", B = "2", C="5")
type SumDigit<A extends string, B extends string, C extends string> =
ArrToSum<StrToArr<LastDigit<A>>, StrToArr<LastDigit<B>>, StrToArr<C>>
// extract the last digit (e.g., extract "4" from "1234")
type LastDigit<T extends string> = T extends `${infer P}${infer Q}`
? Q extends ""
? P
: LastDigit<Q>
: "";
// extract the digits other than the laast digit (e.g., extract "123" from "1234")
type RestDigits<T extends string> = T extends ""
? ""
: T extends `${infer P}${infer Q}`
? Q extends ""
? ""
: `${P}${RestDigits<Q>}`
: "";
// main calculation logic. takes A, B, and Carry.
// Carry represents the carry digit from previous digit calculation.
// the calculation is done recursively, digit by digit.
type _Sum<
A extends string,
B extends string,
Carry extends string = "0"
> = `${A}${B}${Carry}` extends ""
? ""
: `${_Sum<
RestDigits<A>,
RestDigits<B>,
RestDigits<SumDigit<A, B, Carry>>
>}${LastDigit<SumDigit<A, B, Carry>>}`;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = _Sum<`${A}`, `${B}`>;
Solution by nakaakist #30497
// 你的答案
type STN<T extends string> = T extends `${infer F extends number}` ? F : never
type NTS<T extends string | number | bigint> = `${T}`
type NTA<T extends number, U extends ''[] = []> = U['length'] extends T ? U : NTA<T, [...U, '']>
type NTAR<T extends string | number | bigint, TS extends string = NTS<T>> = TS extends `${infer F}${infer R}` ? [STN<F>, ...NTAR<T, R>] : []
type NumAddR<T extends number, U extends number, Y extends number = 0, TA extends ''[] = NTA<T>, UA extends ''[] = NTA<U>> =
[...TA, ...UA, ...NTA<Y>] extends [...NTA<10>, ...infer R] ? R['length'] : [...TA, ...UA, ...NTA<Y>]['length']
type NumAddG<T extends number, U extends number, Y extends number = 0, TA extends ''[] = NTA<T>, UA extends ''[] = NTA<U>> =
[...TA, ...UA, ...NTA<Y>] extends [...NTA<10>, ...any] ? true : false
type ATS<T extends number[]> = T extends [infer F extends number, ...infer R extends number[]] ? `${F}${ATS<R>}` : ''
type Sum<A extends string | number | bigint, B extends string | number | bigint, AA extends number[] = (A extends string ? NTAR<STN<A>> : NTAR<A>), BA extends number[] = (B extends string ? NTAR<STN<B>> : NTAR<B>), C extends any[] = [], Y extends boolean = false> =
AA extends [...infer AR extends number[], infer AL extends number] ?
BA extends [...infer BR extends number[], infer BL extends number] ?
Sum<A, B, AR, BR, [NumAddR<AL, BL, Y extends true ? 1 : 0>, ...C], NumAddG<AL, BL, Y extends true ? 1 : 0>> :
Sum<A, B, AR, [], [NumAddR<AL, 0, Y extends true ? 1 : 0>, ...C], NumAddG<AL, 0, Y extends true ? 1 : 0>> :
ATS<Y extends true ? [1, ...BA, ...C] : [...BA, ...C]>
Solution by YE840926098 #30187
type AddMap = [
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
['2', '3', '4', '5', '6', '7', '8', '9', '10', '11'],
['3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
['4', '5', '6', '7', '8', '9', '10', '11', '12', '13'],
['5', '6', '7', '8', '9', '10', '11', '12', '13', '14'],
['6', '7', '8', '9', '10', '11', '12', '13', '14', '15'],
['7', '8', '9', '10', '11', '12', '13', '14', '15', '16'],
['8', '9', '10', '11', '12', '13', '14', '15', '16', '17'],
['9', '10', '11', '12', '13', '14', '15', '16', '17', '18']
];
type Reverse<S extends string> = S extends `${infer E}${infer R}`
? `${Reverse<R>}${E}`
: S; //反转字符串 从低位开始算
type Get<X, Y> = X extends keyof AddMap
? Y extends keyof AddMap[X]
? AddMap[X][Y]
: '0'
: '0'; //从 Map 中取运算结果
type AddTwo<A extends string, B extends string> = B extends ''
? A
: A extends `1${infer R}${infer N}`
? `1${Get<R, B>}`
: Get<A, B>; // 加两个单位数
type AddThree<A extends string, B extends string, C extends string> = AddTwo<
AddTwo<A, B>,
C
>; // 加三个单位数 第三个数为进位
type SumString<
A extends string,
B extends string,
E extends string = ''
> = A extends `${infer A1}${infer A2}`
? B extends `${infer B1}${infer B2}`
? `${AddThree<A1, B1, E> extends `1${infer S}${infer N}`
? S
: AddThree<A1, B1, E>}${SumString<
A2,
B2,
AddThree<A1, B1, E> extends `1${infer S}${infer N}` ? '1' : ''
>}`
: E extends ''
? A
: SumString<A, '1'>
: E extends ''
? B
: SumString<'1', B>;
type Format<S extends string> = S extends `${infer L}_${infer R}`
? `${L}${Format<R>}`
: S extends `${infer A}n${infer B}`
? `${A}${Format<B>}`
: S; //格式化特殊数字
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = Reverse<SumString<Reverse<Format<`${A}`>>, Reverse<Format<`${B}`>>>>;
Solution by Royce-DaDaDa #29811
// Utils
type NumberToTuple<N extends number, T extends 1[] = []> = T['length'] extends N
? T
: NumberToTuple<N, [...T, 1]>;
type Reverse<S extends string> = S extends `${infer F}${infer R}`
? `${Reverse<R>}${F}`
: S;
type ToNumber<T> = T extends number ? T : never;
// Helper types
type CarryOver<N extends number> =
`${N}` extends `${infer _}${infer __ extends number}` ? 1 : 0;
type LastDigit<N extends number> =
`${N}` extends `${infer _}${infer D extends number}` ? D : N;
type Add<A extends number, B extends number> = ToNumber<
[...NumberToTuple<A>, ...NumberToTuple<B>]['length']
>;
type StringSum<
A extends string,
B extends string,
C extends number = 0
> = A extends `${infer AF extends number}${infer AR}`
? B extends `${infer BF extends number}${infer BR}`
? `${LastDigit<Add<Add<AF, BF>, C>>}${StringSum<
AR,
BR,
CarryOver<Add<Add<AF, BF>, C>>
>}`
: `${LastDigit<Add<AF, C>>}${CarryOver<Add<AF, C>> extends 1
? StringSum<AR, '', 1>
: AR}`
: B extends `${infer BF extends number}${infer BR}`
? `${LastDigit<Add<BF, C>>}${CarryOver<Add<BF, C>> extends 1
? StringSum<'', BR, 1>
: BR}`
: C extends 0
? ''
: `${C}`;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = Reverse<StringSum<Reverse<`${A}`>, Reverse<`${B}`>>>;
Solution by JohnLi1999 #27456
/**0~9 */
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
/**个位 RRRF ==> F */
type DigitFirst<T extends string | number | bigint> = T extends string ?
(Number<T> extends Digit ?
Number<T> :
(T extends `${number}${infer R}` ? DigitFirst<R> : never)) :
DigitFirst<`${T}`>;
/**个位以上 RRRF ==> RRR */
type DigitRest<T extends string | number | bigint, _Result extends string = ``> = T extends string ?
(T extends `${infer F}${infer R extends `${any}${any}`}` ?
DigitRest<R, `${_Result}${F}`> :
_Result) :
DigitRest<`${T}`>;
type MakeCounter<T extends number, _Result extends 1[] = []> = _Result[`length`] extends T ? _Result : MakeCounter<T, [..._Result, 1]>;
/**个位相加 */
type DigitAdd<X extends Digit, Y extends Digit> = [...MakeCounter<X>, ...MakeCounter<Y>][`length`] extends (infer N extends number) ? N : 0;
/**Parse Int */
type Number<T extends string | number> = T extends `${infer F extends number}` ? F : 0;
/**+1(进位) */
type AddOne<T extends number | string, _DigitAdd extends number = DigitAdd<DigitFirst<T>, 1>> = `${_DigitAdd extends Digit ? DigitRest<T> : /*进位*/AddOne<DigitRest<T>>}${DigitFirst<_DigitAdd>}`;
/**加法器(自然数) */
type Sum<A extends string | number | bigint, B extends string | number | bigint, _Result extends string = ``, _DigitAdd extends number = DigitAdd<DigitFirst<A>, DigitFirst<B>>> =
`${A}${B}` extends `` ? _Result : //return
Sum<DigitRest<A>, _DigitAdd extends Digit ? DigitRest<B> : /*进位*/AddOne<DigitRest<B>>, `${DigitFirst<_DigitAdd>}${_Result}`>;
Solution by E-uler #25526
type StrDigitRangeMap = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
type StringDigit = StrDigitRangeMap[number]
type DigitRangeMap = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
type Digit = DigitRangeMap[number]
type RoundMap = {
10: 0
11: 1
12: 2
13: 3
14: 4
15: 5
16: 6
17: 7
18: 8
19: 9
20: 9
}
type GenerateArray<F extends number, L, E extends number[]> = E['length'] extends L
? E
: GenerateArray<F, L, [F, ...E]>
type creatArray<L extends number = 0> = number extends L ? 1[] : GenerateArray<1, L, []>
type addition<A extends number, B extends number> = [...creatArray<A>, ...creatArray<B>]['length']
type NumberToString<
T extends number | string | bigint,
R extends string = ''
> = `${T}` extends `${infer F}${infer Res}`
? NumberToString<Res, `${R}${F extends StringDigit ? F : ''}`>
: R
type ToDigit<T extends string> = T extends keyof DigitRangeMap ? DigitRangeMap[T] : ''
type ToDigitList<T, R extends any[] = []> = T extends `${infer First}${infer Rest}`
? ToDigitList<Rest, [ToDigit<First>, ...R]>
: R
type computed<
T extends number[] = [],
U extends number[] = [],
Pre extends any[] = [],
L extends number = Pre['length']
> = T[L] extends number
? U[L] extends number
? computed<T, U, [...Pre, addition<T[L], U[L]>]>
: computed<T, U, [...Pre, T[L] extends number ? T[L] : never]>
: U[L] extends number
? computed<T, U, [...Pre, U[L] extends number ? U[L] : never]>
: Pre
type computedArray<T extends any[] = [], P extends any[] = [], Add extends any[] = []> =
T extends [ First: infer F, ...Rest: infer R ]
? F extends Digit
? computedArray<
R,
[
...P,
Add['length'] extends 0
? F
: addition<F, Add['length']> extends keyof RoundMap
? RoundMap[addition<F, Add['length']>]
: addition<F, Add['length']>
],
Add['length'] extends 0
? []
: addition<F, Add['length']> extends keyof RoundMap
? [...Add]
: []
>
: computedArray<
R, //2位数处理
[...P, F extends keyof RoundMap ? addition<RoundMap[F], Add['length']> : never],
F extends keyof RoundMap ? (F extends 19 ? [Add['length'], 0] : [Add['length']]) : []
>
: Add['length'] extends 0
? P
: [...P, Add['length']]
type Join<T extends any[], Separator extends string = '', Result extends string = ''> = T extends [
infer F,
...infer R
]
? F extends Digit
? Join<R, Separator, `${StrDigitRangeMap[F]}${Result extends '' ? '' : Separator}${Result}`>
: never
: Result
type Sum<A extends number | string | bigint, B extends number | string | bigint> = Join<
computedArray<computed<ToDigitList<NumberToString<A>>, ToDigitList<NumberToString<B>>>>
>
Solution by TKBnice #23778
// your answers
type ValueToNumberArray_<
T extends number | string | bigint,
A extends number[] = []
> = T extends `${infer S extends number}${infer R}` ? ValueToNumberArray_<R, [...A, S]> : A
type ValueToNumberArray<
T extends number | string | bigint,
> = T extends number | bigint ? ValueToNumberArray_<`${T}`> : ValueToNumberArray_<T>;
type GetStringArray<T extends string, A extends number[] = []> = T extends `${infer F extends number}${infer R}` ? GetStringArray<R, [...A, F]> : A;
type BuildArray<
Length extends number,
FillVal = unknown,
Arr extends unknown[] = []
> = Arr['length'] extends Length ? Arr : BuildArray<Length, FillVal, [...Arr, FillVal]>;
type SmallSum<A extends number, B extends number> = [...BuildArray<A>, ...BuildArray<B>]['length'];
type SumForArray<
A extends number[],
B extends number[],
> = A extends [...infer RA extends number[], infer LA extends number]
? B extends [...infer RB extends number[], infer LB extends number]
? [...SumForArray<RA, RB>, SmallSum<LA, LB>]
: [...SumForArray<RA, []>, LA]
: B extends [...infer RB extends number[], infer LB extends number]
? [...SumForArray<RB, []>, LB]
: [];
type AddOne<T extends number | undefined> = T extends number ? SmallSum<T, 1> : 1;
type NumberArrToStr<
T extends number[],
Str extends string= '',
IsOverflow extends boolean = false
> = T extends [...infer F extends number[], infer L extends number]
? IsOverflow extends true
? GetStringArray<`${L}`>['length'] extends 2
? `${NumberArrToStr<F, `${AddOne<GetStringArray<`${L}`>[1]>}${Str}`, true>}`
: AddOne<GetStringArray<`${L}`>[0]> extends 10
? `${NumberArrToStr<F, `0${Str}`, true>}`
: `${NumberArrToStr<F, `${AddOne<GetStringArray<`${L}`>[0]>}${Str}`, false>}`
: GetStringArray<`${L}`>['length'] extends 2
? `${NumberArrToStr<F, `${GetStringArray<`${L}`>[1]}${Str}`, true>}`
: `${NumberArrToStr<F, `${GetStringArray<`${L}`>[0]}${Str}`, false>}`
: IsOverflow extends true ? `1${Str}` : Str;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = NumberArrToStr<SumForArray<ValueToNumberArray<A>, ValueToNumberArray<B>>>;
Solution by jxhhdx #23446
/**
* @example
* type Result = Sum<15, 8> // '23'
*
* type Step1A = NumberToArray<15> // [[0], [0, 0, 0, 0, 0]]
* type Step1B = NumberToArray<8> // [[0, 0, 0, 0, 0, 0, 0, 0]]
*
* type Step2 = AddArray<Step1A, Step1B> // [[0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
*
* type Step3 = StRegulateArrayNumber<Step2> // [[0, 0], [0, 0, 0]]
*
* type Step4 = RegulatedArrayNumberToStringNumber<Step3> // '23'
*/
type Sum<
A extends string | number | bigint,
B extends string | number | bigint,
> =
RegulatedArrayNumberToStringNumber<
RegulateArrayNumber<
AddArray<
NumberToArray<A>,
NumberToArray<B>
>
>
>
type NumberToArray<T extends string | number | bigint, R extends 0[][] = []> =
`${T}` extends `${infer A extends number}${infer Rest}`
? NumberToArray<Rest, [...R, DigitToArray<A>]>
: R
type DigitToArray<T extends number, R extends 0[] = []> =
R['length'] extends T
? R
: DigitToArray<T, [...R, 0]>
type AddArray<
A extends 0[][],
B extends 0[][],
R extends 0[][] = [],
> =
A extends [...infer AR extends 0[][], infer AL extends 0[]]
? B extends [...infer BR extends 0[][], infer BL extends 0[]]
? AddArray<AR, BR, [[...AL, ...BL], ...R]>
: [...A, ...R]
: [...B, ...R]
type ArrayOf10 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
type RegulateArrayNumber<T extends 0[][], R extends 0[][] = []> =
T extends []
? R
: T extends [...infer Rest extends 0[][], infer L2 extends 0[], infer L1 extends 0[]]
? L1 extends [...ArrayOf10, ...infer More extends 0[]]
? RegulateArrayNumber<[...Rest, [...L2, 0]], [More, ...R]>
: RegulateArrayNumber<[...Rest, L2], [L1, ...R]>
: T[0] extends [...ArrayOf10, ...infer More extends 0[]]
? RegulateArrayNumber<[[0]], [More, ...R]>
: RegulateArrayNumber<[], [T[0], ...R]>
type RegulatedArrayNumberToStringNumber<T extends 0[][], R extends string = ''> =
T extends [infer A extends 0[], ...infer Rest extends 0[][]]
? RegulatedArrayNumberToStringNumber<Rest, `${R}${A['length']}`>
: R
Solution by drylint #23343
type IntADT = number | string | bigint;
type DigitLUT = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
type Digit = DigitLUT[number];
type Sum<
A extends IntADT,
B extends IntADT,
SUM_TUPLE extends Digit[] = $sum<A, B>,
RESULT extends IntADT = Join<SUM_TUPLE>,
> = RESULT;
type $sum<
A extends IntADT,
B extends IntADT,
A_TUPLE extends Digit[] = IntToTuple<A>,
B_TUPLE extends Digit[] = IntToTuple<B>,
OUTPUT extends Digit[] = [],
CARRY_IN extends 0 | 1 = 0,
A_LSD extends Digit = A_TUPLE extends [] ? '0' : Last<A_TUPLE, Digit>,
B_LSD extends Digit = B_TUPLE extends [] ? '0' : Last<B_TUPLE, Digit>,
SUM extends number = Add<CARRY_IN, Add<A_LSD, B_LSD>>,
CURR extends Digit = LSD<SUM>,
CARRY_OUT extends 0 | 1 = `${SUM}` extends `${CURR}` ? 0 : 1,
NEXT extends Digit[] = Unshift<OUTPUT, CURR>,
RESULT extends Digit[] = All<[Equal<A_TUPLE["length"], 0>, Equal<B_TUPLE["length"], 0>]> extends true
? CARRY_IN extends 1 ? Unshift<OUTPUT, '1'> : OUTPUT
: $sum<A, B, Pop<A_TUPLE>, Pop<B_TUPLE>, NEXT, CARRY_OUT>,
> = RESULT;
$sum
into Sum
, or, more specifically, composing Join<$sum<A, B>>
results in this error:
TS2590: Expression produces a union type that is too complex to represent.
/** @returns Digit */
type LSD<N extends IntADT> =
`${N}` extends `${string}${infer Rest extends `${infer H}${infer D extends Digit}`}`
? LSD<Rest>
: `${N}` extends `${infer X extends Digit}` ? X : never;
type IntToTuple<
N extends IntADT,
OUTPUT extends Digit[] = [],
CURR extends Digit = `${N}` extends `${infer D extends Digit}${string}` ? D : never,
NEXT extends string = `${N}` extends `${CURR}${infer Rest}` ? Rest : never,
RESULT extends Digit[] = N extends `` ? OUTPUT : IntToTuple<NEXT, Push<OUTPUT, CURR>>,
> = RESULT;
type Join<T extends any[], OUTPUT extends string = ``> =
T extends [T[0], ...infer Rest]
? Join<Rest, `${OUTPUT}${T[0]}`>
: OUTPUT;
/** @returns number | never */
type Subtract<M extends IntADT, S extends IntADT> =
`${M}` extends `${infer A extends number}`
? `${S}` extends `${infer B extends number}`
? Repeat<A> extends [...Repeat<B>, ...infer Rest] ? Rest["length"] : never
: A
: never;
/** @returns number */
type Add<A extends IntADT, B extends IntADT> =
`${A}` extends `${infer X extends number}`
? `${B}` extends `${infer Y extends number}`
? Concat<Repeat<X>, Repeat<Y>>["length"]
: X
: `${B}` extends `${infer Y extends number}`
? Y
: 0;
type All<T extends boolean[]> =
T extends [infer B, ...infer Rest extends boolean[]]
? B extends true ? All<Rest> : false
: true;
type Last<T extends U[], U = any> =
T extends [...infer _, infer P extends U] ? P : never;
type Shift<T extends unknown[], N extends number = 1> =
N extends 0 ? T
: T extends [infer _, ...infer Rest]
? Shift<Rest, Subtract<N, 1>>
: [];
type Unshift<T extends unknown[], U extends unknown> =
[U, ...T];
type Push<T extends unknown[], U extends unknown> =
[...T, U];
type Concat<T extends unknown[], U extends unknown[]> =
[...T, ...U];
type Repeat<N extends number, T extends unknown = null, M extends T[] = []> =
M["length"] extends N ? M : Repeat<N, T, Push<M, T>>;
Solution by MajorLift #22402
type GreaterThanOrEqual<
T extends number,
U extends number,
A extends any[] = [],
> = T extends U
? true : A['length'] extends T
? false
: A['length'] extends U
? true
: GreaterThan<T, U, ['a', ...A]>
type SumAll<A extends number[], Arr extends unknown[] = []> =
A extends [infer F extends number, ...infer R extends number[] ]
? SumAll<R, [...Arr, ...LengthToArray<F>]>
: `${Arr['length']}`
type SumArr<
A extends string[],
B extends string[],
SS extends string = '',
K extends number = 0,
> = GreaterThanOrEqual<A['length'], B['length']> extends true
? A extends [...infer ROA extends string[], `${infer LOA extends number}`]
? B extends [...infer ROB extends string[], `${infer LOB extends number}`]
? SumAll<[LOA, LOB, K]> extends `${infer F}${infer S}`
? S extends ''
? SumArr<ROA, ROB, `${F}${SS}`>
: SumArr<ROA, ROB, `${S}${SS}`, 1>
: never
: SumAll<[LOA, K]> extends `${infer F}${infer S}`
? S extends ''
? SumArr<ROA, ['0'], `${F}${SS}`>
: SumArr<ROA, ['0'], `${S}${SS}`, 1>
: never
: K extends 1
? `1${SS}`
: SS
: A['length'] extends 0
? SumArr<A, [], SS, K>
: SumArr<B, A>
type Sum<
A extends string | number | bigint,
B extends string | number | bigint,
> = SumArr<Split<`${A}`, ''>, Split<`${B}`, ''>>
Solution by thanhhtse04588 #22273
// your answers
type NeedingCarryBit = `${1 | 2}${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`;
// 20 => [0, 2]
type TransForm = {
[P in NeedingCarryBit]: P extends `${infer F extends number}${infer R extends number}`
? [R, F]
: never;
};
// ADD 较小的两个数相加
type Add<
A extends number,
B extends number,
CountA extends 0[] = [],
CountB extends 0[] = []
> = CountA["length"] extends A
? CountB["length"] extends B
? [...CountA, ...CountB]["length"]
: Add<A, B, CountA, [0, ...CountB]>
: CountB["length"] extends B
? Add<A, B, [0, ...CountA], CountB>
: Add<A, B, [0, ...CountA], [0, ...CountB]>;
// 判断两个数字的大小
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 ReverseString<S extends string> = S extends `${infer F}${infer R}`
? `${ReverseString<R>}${F}`
: "";
// 获取字符串长度
type GetStringLength<
S extends string,
I extends 0[] = []
> = S extends `${string}${infer R}`
? GetStringLength<R, [0, ...I]>
: I["length"];
type StringNumberAdd<
A extends string,
B extends string,
Jw extends number = 0
> = A extends `${infer AF extends number}${infer AR}`
? B extends `${infer BF extends number}${infer BR}`
? Add<AF, Add<BF, Jw>> extends infer AFBF extends number
? `${AFBF}` extends keyof TransForm
? `${TransForm[`${AFBF}`][0]}${StringNumberAdd<
AR,
BR,
TransForm[`${AFBF}`][1]
>}`
: `${AFBF}${StringNumberAdd<AR, BR, 0>}`
: never
: Jw extends 0
? A
: Add<Jw, AF> extends infer AFJW extends number
? `${AFJW}` extends keyof TransForm
? `${TransForm[`${AFJW}`][0]}${StringNumberAdd<
AR,
"",
TransForm[`${AFJW}`][1]
>}`
: `${AFJW}${StringNumberAdd<AR, "", 0>}`
: never
: Jw extends 0
? ""
: `${Jw}`;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = ReverseString<
GreaterThan<GetStringLength<`${A}`>, GetStringLength<`${B}`>> extends true
? StringNumberAdd<ReverseString<`${A}`>, ReverseString<`${B}`>>
: StringNumberAdd<ReverseString<`${B}`>, ReverseString<`${A}`>>
>;
Solution by acwink #22210
// reverse a string
type ReverseString<S extends string> = S extends `${infer F}${infer Rest}` ? `${ReverseString<Rest>}${F}` : ''
// convert number to tuple, tail-recursion
type Number2Tuple<N extends number, _T extends unknown[] = []> = _T['length'] extends N ? _T : Number2Tuple<N, [..._T, unknown]>
// sum two numbers
type SumNumber<A extends number, B extends number> = [...Number2Tuple<A>, ...Number2Tuple<B>]['length'] & number
// sum two numbers in reversed string format
type SumReversedString<A extends string, B extends string> =
A extends `${infer AF extends number}${infer ARest}`
? B extends `${infer BF extends number}${infer BRest}`
? ReverseString<`${SumNumber<AF, BF>}`> extends `${infer Gewei}${infer Shiwei}`
? `${Gewei}${SumReversedString<ARest, SumReversedString<BRest, Shiwei>>}`
: never
: A
: B
type Sum<A extends string | number | bigint, B extends string | number | bigint> = ReverseString<SumReversedString<ReverseString<`${A}`>, ReverseString<`${B}`>>>
Key points:
SumReversedString
recursively to handle carry-bit problem to reduce a lot of detailsSolution by zhaoyao91 #22195
// your answers
/** SumA if A=3 C='' then '01234567890123456789' >>> '34567890123456789' */
/** SumB if B=2 C='' then '34567890123456789' >>> '567890123456789' */
/** 最终字符串的第一个字母就是结果,并且字符串里没有 '90' 说明已经进位。 */
type SumB<N extends number, S extends string, T extends any[] = []>
= S extends `${infer F}${infer L}`
? T['length'] extends N
? [F, S extends `${string}90${string}` ? '' : '1']
: SumB<N, L, [...T, 0]>
: never
type SumA<
A extends string, B extends string, C extends string = '', S extends string = '01234567890123456789'>
= SumB<B extends `${infer N extends number}` ? N : never,
S extends `${string}${A}${infer L}` ? `${C extends '' ? A : ''}${L}` : S>
type REVSum<
A extends string, B extends string, C extends string = '', S extends string = ''>
= [...(A extends `${infer AA}${infer AAA}` ? [AA, AAA] : ['', '']),
...(B extends `${infer BB}${infer BBB}` ? [BB, BBB] : ['', '']),
] extends [
infer AA extends string, infer AAA extends string,
infer BB extends string, infer BBB extends string
] ? (
[AA | AAA | C extends '' ? 1 : 0, BB | BBB | C extends '' ? 1 : 0,] extends [0, 0]
? (SumA<(AA extends '' ? '0' : AA), (BB extends '' ? '0' : BB), C> extends [
infer SS extends string, infer CC extends string]
? REVSum<AAA, BBB, CC, `${S}${SS}`>
: 'useless')
: REV<`${S}${AA}${BB}${AAA}${BBB}`>
) : 'useless'
type REV<S, R extends string = ''> = S extends `${infer F}${infer L}` ? REV<L, `${F}${R}`> : R
type Sum<A extends string | number | bigint, B extends string | number | bigint>
= `${A}=${B} ` extends `${infer AA}=${infer BB} ` ? REVSum<REV<AA>, REV<BB>> : ['error number', A, B]
Solution by goddnsgit #22168
type _Number2Array<
N extends string,
_AddOne extends boolean = false,
_Result extends 0[] = [],
_NN extends number = `${ N }` extends `${ infer I extends number }` ? I : never,
> = _Result['length'] extends _NN
? _AddOne extends false ? _Result : [ 0, ..._Result ]
: _Number2Array<N, _AddOne, [ ..._Result, 0 ]>
type _TwoSingleDigitSum<
A extends _DigitString,
B extends _DigitString,
_PlusOne extends boolean = false,
_Carry extends boolean = false,
_Counter extends 0[] = [],
_SumArray extends unknown[] = [ ..._Number2Array<A, _PlusOne>, ..._Number2Array<B> ],
> = _Counter['length'] extends 10
? _TwoSingleDigitSum<A, B, _PlusOne, true>
: _Carry extends false
? _Counter['length'] extends _SumArray['length']
? { carry: false, digit: _Counter['length'] }
: _TwoSingleDigitSum<A, B, _PlusOne, false, [ ..._Counter, 0 ]>
: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ..._Counter ]['length'] extends _SumArray['length']
? { carry: true, digit: _Counter['length'] }
: _TwoSingleDigitSum<A, B, _PlusOne, true, [ ..._Counter, 0 ]>
type _DigitString = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
type _GetLast<T extends string | number | bigint, _Rest extends string = ''> = `${ T }` extends _DigitString
? { rest: _Rest, last: `${ T }` }
: `${ T }` extends `${ infer Rest extends string }${ infer I extends string }`
? _GetLast<I, `${ _Rest }${ Rest }`>
: { rest: '', last: '0' }
type Sum<
A extends string | number | bigint,
B extends string | number | bigint,
_PlusOne extends boolean = false,
_Result extends string = '',
_AL extends { rest: string, last: _DigitString } = _GetLast<A>,
_BL extends { rest: string, last: _DigitString } = _GetLast<B>,
_LastSum extends { carry: boolean, digit: number } = _TwoSingleDigitSum<_AL['last'], _BL['last'], _PlusOne>,
> = `${ _AL['rest'] }${ _BL['rest'] }` extends ''
? `${ _LastSum['carry'] extends true ? 1 : '' }${ _LastSum['digit'] }${ _Result }`
: Sum<_AL['rest'], _BL['rest'], _LastSum['carry'], `${ _LastSum['digit'] }${ _Result }`>
Solution by lvjiaxuan #22107
type Build<
T extends number,
Result extends Array<never> = []
> = Result["length"] extends T ? Result : Build<T, [...Result, never]>;
type Add<A extends number, B extends number> = [
...Build<A>,
...Build<B>
]["length"];
type stringToNumber<T> = `${T & string}` extends `${infer A extends number}`
? A
: never;
type Add2<A extends number, B extends number> = `${Add<A, B> &
number}` extends `1${infer G extends number}`
? {
overflow: 1;
value: G;
}
: {
overflow: 0;
value: Add<A, B>;
};
type Reverse<T extends string | number | bigint> =
`${T}` extends `${infer A}${infer B}` ? `${Reverse<B>}${A}` : T;
type GetSLast<
T extends string | number | bigint,
B extends string | number | bigint
> = [
`${T}` extends `${infer A}${infer B}` ? stringToNumber<A> : "",
`${B}` extends `${infer A}${infer B}` ? stringToNumber<A> : ""
];
type GetSOther<T extends string | number | bigint> =
`${T}` extends `${infer A}${infer B}` ? B : "";
type GetHaveString<A, B> = A extends "" ? B : A;
type Sum1<
A extends string | number | bigint,
B extends string | number | bigint,
Overflow extends number = 0,
Result extends string = ""
> = [""] extends [A | B]
? [A, B] extends ["", ""]
? `${Result}${Overflow extends 0 ? "" : Overflow}`
: GetHaveString<A, B> extends `${infer Z}`
? Z extends ""
? Result
: Sum1<Z, Overflow, 0, Result>
: never
: GetSLast<A, B> extends [infer A1 extends number, infer B1 extends number]
? Add2<Add<A1, Overflow> & number, B1> extends {
overflow: infer O extends number;
value: infer V;
}
? Sum1<GetSOther<A>, GetSOther<B>, O, `${Result}${V & number}`>
: never
: Result;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = Reverse<Sum1<Reverse<A>, Reverse<B>>>
Solution by so11y #21557
type IsEmpty<S> = S extends ('' | []) ? true : false;
type And<B1 extends boolean, B2 extends boolean> = B1 extends true ? (B2 extends true ? true : false) : false;
// Create array of N length
type NArray<N extends number, A extends any[]= []> = A['length'] extends N ? A : NArray<N, [...A, never]>;
// Normalize number to string
type NumToStr<N extends string | number | bigint> = N extends (number | bigint) ? `${N}`
: N extends `${infer Num extends bigint}` ? `${Num}` : never;
// Sum small numbers
type EnsureNum<N> = N extends number ? N : never;
type SumSmall<N1 extends number, N2 extends number, N3 extends number> = EnsureNum<[...NArray<N1>, ...NArray<N2>, ...NArray<N3>]['length']>;
// type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
type DigitArray<S> = S extends `${infer D extends number}${infer R}` ? [...DigitArray<R>, D] : []
type ArrayToNum<Arr> = Arr extends [infer T1 extends number, ...infer TR] ? `${ArrayToNum<TR>}${T1}` : '';
type FirstDig<Arr> = Arr extends [infer T1, ...infer TR] ? T1 : 0;
type SecondDig<Arr> = Arr extends [infer T1, infer T2, ...infer TR] ? T2 : 0;
type NextDig<Arr> = Arr extends [infer T1, ...infer TR] ? TR : [];
type SumDigits<
Arr1 extends number[], Arr2 extends number[],
PrevC extends number = 0,
SumFirst extends number[] = DigitArray<`${SumSmall<FirstDig<Arr1>, FirstDig<Arr2>, PrevC>}`>,
NextC extends number = SecondDig<SumFirst>,
TotalDigit extends number= FirstDig<SumFirst>,
> = And<IsEmpty<Arr1>, IsEmpty<Arr2>> extends true ? (TotalDigit extends 0 ? [] : [TotalDigit])
: [TotalDigit, ...SumDigits<NextDig<Arr1>, NextDig<Arr2>, NextC>]
type Sum<A extends string | number | bigint, B extends string | number | bigint> =
ArrayToNum<SumDigits<DigitArray<NumToStr<A>>, DigitArray<NumToStr<B>>>>
Solution by mdakram28 #20675
type ParseInt<T extends string | number> = T extends `${ infer V extends number }` ? V : 0;
type Length<T extends any[]> = T['length'] extends number ? T['length'] : never;
type ArrayFromString<T extends number, Result extends any[] = []> =
Result['length'] extends T
? Result
: ArrayFromString<T, [any, ...Result]>;
type Add<
A extends number,
B extends number,
I extends boolean = false,
S extends number = Length<[...ArrayFromString<A>, ...ArrayFromString<B>, ...(I extends true ? [any] : [])]>
> = `${ S }` extends `1${ infer V extends number }`
? [true, V, S]
: [false, S, S];
type LastIndexOf<T extends string> = T extends `${ infer F }${ infer R }` ? R extends '' ? F : LastIndexOf<R> : '';
type PopString<T extends string, Result extends string = ''> =
T extends `${ infer L }${ infer R }`
? R extends ''
? Result
: PopString<R, `${ Result }${ L }`>
: ''
type RemovePreZero<T extends string> = T extends `0${ infer V }` ? V extends '' ? T : RemovePreZero<V> : T;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint,
I extends boolean = false,
Result extends string = '',
AL extends string = LastIndexOf<`${ A }`>,
BL extends string = LastIndexOf<`${ B }`>,
> =
Add<ParseInt<AL>, ParseInt<BL>, I> extends [infer Increase extends boolean, infer Value extends number, infer V extends number]
? AL extends ''
? BL extends ''
? RemovePreZero<`${ V }${ Result }`>
: Sum<PopString<`${ A }`>, PopString<`${ B }`>, Increase, `${ Value }${ Result }`>
: Sum<PopString<`${ A }`>, PopString<`${ B }`>, Increase, `${ Value }${ Result }`>
: never
;```
Solution by xiexuan-star #20635
type NumberWithinTen<
T extends string | number,
R extends unknown[] = []
> = `${R['length']}` extends `${T}` ? R : NumberWithinTen<T, [unknown, ...R]>
type StringToNumberArray<T extends string> = T extends `${infer A}${infer B}`
? [NumberWithinTen<A>, ...StringToNumberArray<B>]
: []
type Reverse<T extends unknown[]> = T extends [infer A, ...infer B]
? [...Reverse<B>, A]
: []
type Shift<T extends unknown[]> = T extends [unknown, ...infer A] ? A : T
type RemoveRightZero<T extends string> = T extends `0${infer A}`
? A extends ''
? '0'
: RemoveRightZero<A>
: T
type SumUnit<
A extends unknown[] | undefined,
B extends unknown[] | undefined,
C extends boolean = false
> = A extends unknown[]
? B extends unknown[]
? C extends true
? [...A, ...B, unknown]
: [...A, ...B]
: C extends true
? [...A, unknown]
: A
: B extends unknown[]
? C extends true
? [...B, unknown]
: B
: C extends true
? [unknown]
: undefined
type BasicSum<
A extends string | number | bigint,
B extends string | number | bigint,
Carry extends boolean = false,
AInNumberArray extends unknown[][] = Reverse<StringToNumberArray<`${A}`>>,
BInNumberArray extends unknown[][] = Reverse<StringToNumberArray<`${B}`>>,
UnitSum extends string = SumUnit<
AInNumberArray[0],
BInNumberArray[0],
Carry
> extends unknown[]
? `${SumUnit<AInNumberArray[0], BInNumberArray[0], Carry>['length']}`
: ''
> = UnitSum extends `${infer SU1}${infer SU2}`
? `${BasicSum<
A,
B,
SU2 extends '' ? false : true,
Shift<AInNumberArray>,
Shift<BInNumberArray>
>}${SU2 extends '' ? SU1 : SU2}`
: UnitSum
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> =
// @ts-ignore
RemoveRightZero<BasicSum<A, B>>
Solution by theoolee #19884
type DigitMap = {
'0': [],
'1': [1],
'2': [1, 1],
'3': [1, 1, 1],
'4': [1, 1, 1, 1],
'5': [1, 1, 1, 1, 1],
'6': [1, 1, 1, 1, 1, 1],
'7': [1, 1, 1, 1, 1, 1, 1],
'8': [1, 1, 1, 1, 1, 1, 1, 1],
'9': [1, 1, 1, 1, 1, 1, 1, 1, 1],
}
type Zero = [];
type One = [1];
type Carry = Zero | One;
type Ten = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
type Digit = keyof DigitMap;
type MinusTen<S extends 1[]> =
S extends [...Ten, ...infer R] ? `${R['length']}` & Digit : never;
type DigitSum<
A extends Digit,
B extends Digit,
C extends Carry = Zero,
S extends 1[] = [...DigitMap[A], ...DigitMap[B], ...C]
> =
`${S['length']}` extends Digit
? [Zero, `${S['length']}`]
: [One, MinusTen<S>];
type SumStr<
A extends Digit[],
B extends Digit[],
R extends [Carry, Digit]
> =
R extends [infer C extends Carry, infer N extends Digit]
? `${SumArr<A, B, C>}${N}`
: never
type SumArr<
A extends Digit[],
B extends Digit[],
C extends Carry = Zero
> =
[A, B] extends [
[infer DA extends Digit, ...infer RA extends Digit[]],
[infer DB extends Digit, ...infer RB extends Digit[]]
]
? SumStr<RA, RB, DigitSum<DA, DB, C>>
: A extends [infer D extends Digit, ...infer R extends Digit[]]
? SumStr<R, Zero, DigitSum<D, '0', C>>
: B extends Zero
? C extends Zero ? '' : '1'
: SumArr<B, Zero, C>;
type DigitArr<S extends string> = S extends `${infer F}${infer R}` ? [...DigitArr<R>, F] : Zero;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = SumArr<DigitArr<`${A}`>, DigitArr<`${B}`>>;
Solution by BulatDashiev #16992
// your answers
type ParamType = string | number | bigint
type NumberToTuple<T extends number, R extends 0[] = []> = R['length'] extends T
? R
: NumberToTuple<T, [0, ...R]>
/**
* Split<12> // [1, 2]
* Split<'1'> // [1]
*/
type Split<S extends ParamType, Result extends number[] = []> = `${S}` extends `${infer F extends number}${infer R}`
? Split<R, [...Result, F]>
: Result
/**
* SingleSum<1, 2> // 3
* SingleSum<4, 8> // 12
*/
type SingleSum<T extends number, D extends number> = [...NumberToTuple<T>, ...NumberToTuple<D>]['length'] & number
/**
* GetRest<[1, 2, 3]> // [1, 2]
* GetRest<[1]> // []
*/
type GetRest<T> = T extends [...infer R, infer L extends number]
? R
: []
type Pop<T> = T extends [...infer R, infer L extends number]
? L
: 0
/**
* GetDigit<12> // 2
* GetDigit<1> // 1
*/
type GetDigit<T extends number> = `${T}` extends `${infer F extends number}${infer R extends number}`
? R
: T
/**
* GetTens<12> // 1
* GetTens<1> // 0
*/
type GetTens<T extends number> = `${T}` extends `${infer F extends number}${infer R extends number}`
? F
: 0
type ArraySum<
A extends number[] = [],
B extends number[] = [],
C extends number = 0, // 4 + 8 => 12 => 1
Result extends string = '', // 4 + 8 => 12 => 2 + Result
AL extends number = Pop<A>,
BL extends number = Pop<B>
> = A extends []
? B extends []
? C extends 0 ? Result : `${C}${Result}`
: ArraySum<[], GetRest<B>, GetTens<SingleSum<SingleSum<AL, BL>, C>>, `${GetDigit<SingleSum<SingleSum<AL, BL>, C>>}${Result}`>
: B extends []
? ArraySum<GetRest<A>, [], GetTens<SingleSum<SingleSum<AL, BL>, C>>, `${GetDigit<SingleSum<SingleSum<AL, BL>, C>>}${Result}`>
: ArraySum<GetRest<A>, GetRest<B>, GetTens<SingleSum<SingleSum<AL, BL>, C>>, `${GetDigit<SingleSum<SingleSum<AL, BL>, C>>}${Result}`>
type Sum<
A extends ParamType,
B extends ParamType,
> = ArraySum<Split<A>, Split<B>>
Solution by humandetail #16657
// your answers
type ToString<Val extends string | number | bigint> = `${Val}`;
type StringToNumberArr<Val extends string, Out extends number[] = []> = Val extends ''
? Out
: Val extends `${infer Head extends number}${infer Rest}`
? StringToNumberArr<Rest, [...Out, Head]>
: never;
type ArrLength<Arr extends any[]> = Arr extends { length: infer Length } ? Length : never;
type MakeArrOfLength<Length extends number | bigint, Out extends any[] = []> = Out extends { length: Length } ? Out : MakeArrOfLength<Length, ['', ...Out]>;
type NumberArrToStr<Arr extends number[], Result extends string = ''> = Arr extends { length: 0 }
? Result
: Arr extends [infer First extends number, ...infer Rest extends number[]]
? NumberArrToStr<Rest, `${Result}${First}`>
: never;
type AdderConcatArrs<A extends any[], B extends any[], C extends any[]> = [...A, ...B, ...C];
type Adder<A extends number, B extends number, Carry extends number = 0> = ArrLength<AdderConcatArrs<MakeArrOfLength<A>, MakeArrOfLength<B>, MakeArrOfLength<Carry>>>;
type AdderSum<A extends number, B extends number, Carry extends number = 0> = ToString<Adder<A, B, Carry>> extends `${number}${infer SumDigit extends number}`
? SumDigit
: Adder<A, B, Carry>;
type AdderCarry<A extends number, B extends number, Carry extends number = 0> = ToString<Adder<A, B, Carry>> extends `${infer CarryDigit extends number}${number}`
? CarryDigit
: 0;
type PopArr<Arr extends any[]> = Arr extends { length: 0 }
? []
: Arr extends [...infer Rest, any]
? Rest
: never;
type LongestArr<A extends any[], B extends any[], AAcc extends any[] = A, BAcc extends any[] = B> = AAcc extends { length: 0 }
? B
: BAcc extends { length: 0 }
? A
: LongestArr<A, B, PopArr<AAcc>, PopArr<BAcc>>;
type Max<A extends number, B extends number> = ArrLength<LongestArr<MakeArrOfLength<A>, MakeArrOfLength<B>>>;
type PadStartArr<Arr extends number[], MaxLength extends number> = ToString<MaxLength> extends `-${number}`
? Arr
: Arr extends { length: infer ArrLength extends number }
? ArrLength extends MaxLength
? Arr
: Max<ArrLength, MaxLength> extends MaxLength
? PadStartArr<[0, ...Arr], MaxLength>
: Arr
: Arr;
type SumArrs<A extends number[], B extends number[], Carry extends number = 0, Result extends number[] = []> = A extends { length: ArrLength<B> }
? A extends { length: 0 }
? Carry extends 0 ? Result : [Carry, ...Result]
: A extends [...infer ARest extends number[], infer ALast extends number]
? B extends [...infer BRest extends number[], infer BLast extends number]
? SumArrs<ARest, BRest, AdderCarry<ALast, BLast, Carry>, [AdderSum<ALast, BLast, Carry>, ...Result]>
: never
: never
: SumArrs<PadStartArr<A, ArrLength<LongestArr<A, B>>>, PadStartArr<B, ArrLength<LongestArr<A, B>>>>;
type Sum<A extends string | number | bigint, B extends string | number | bigint> = NumberArrToStr<SumArrs<StringToNumberArr<ToString<A>>, StringToNumberArr<ToString<B>>>>;
Solution by Matt23488 #16607