00476-extreme-sum

Back

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

思路:

  1. 两个数相加应该是按照从右到左,个位数加起来,但是 TS 的推断中只能截取字符串的第1个,因为首先我们先将要加的数翻转,然后从左到右相加
  2. 每一位要相加的2个数,还要加上上一位的进位 AddReturn,结果必然是小于 20,因此继续拆分结果的个位数 V 去和前面的结果 Acc 拼接 ${V}${Acc},然后把进位 Carry 传到下一位的相加运算中
  3. 递归过程中,某个数已经遍历完了,这时候 A 还没遍历完,先判断还有没有进位 1,有的话让 A1 去相加,反之拼接返回 ${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 johncremithq #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];

Solution

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;

Helpers

/** @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}`>>>

playground

Key points:

  1. use template literal to adapt bigint, number, string into string, to standardize the input format
  2. to sum two number from low to high level, reversed string is convenient
  3. to sum two digits, tuple-math is a valid and effective trade-off, while efficient since the range of the problem is so limited (just 2 digits)
  4. use SumReversedString recursively to handle carry-bit problem to reduce a lot of details

中文笔记

Solution 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

Playground

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

// your answers
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 Numerable = string | number | bigint ;

type Stringify<
    N extends Numerable,
    Num extends string =`${N}`> =
    Num extends `${infer R}${infer U}`
    ? R extends keyof Dictionary<any>
    ? `${R}${Stringify<U>}`
    : `${Stringify<U>}`
    : '' ;

type ReverseString<
    S extends string> =
    S extends `${infer R}${infer U}`
    ? `${ReverseString<U>}${R}`
    : ''  ;

type KeyByValue<
    T extends object,
    V extends any,
    Keys extends keyof T = keyof T> =
    Keys extends Keys 
    ? T[Keys] extends V
    ? Keys
    : never
    : never ;

type ReverseStringSum<
    A extends string, 
    B extends string,
    Buff extends readonly any[]=[]> =
    A extends `${infer R extends keyof Dictionary}${infer U extends string}`
    ? B extends `${infer V extends keyof Dictionary}${infer W extends string}`
    ? [...Dictionary[R],...Dictionary[V],...Buff] extends [..._10,...infer S]
    ? `${KeyByValue<Dictionary,S>}${ReverseStringSum<U,W,[any]>}`
    :`${KeyByValue<Dictionary,[...Dictionary[R],...Dictionary[V],...Buff]>}${ReverseStringSum<U,W>}`
    : [...Dictionary[R],...Buff] extends [..._10,...infer S]
    ? `${KeyByValue<Dictionary,S>}${ReverseStringSum<U,'',[any]>}`
    : `${KeyByValue<Dictionary,[...Dictionary[R],...Buff]>}${ReverseStringSum<U,''>}`
    : B extends `${infer V extends keyof Dictionary}${infer W extends string}`
    ? [...Dictionary[V],...Buff] extends [..._10,...infer S]
    ? `${KeyByValue<Dictionary,S>}${ReverseStringSum<'',W,[any]>}`
    : `${KeyByValue<Dictionary,[...Dictionary[V],...Buff]>}${ReverseStringSum<'',W>}`
    : Buff extends [] ? '' : `${KeyByValue<Dictionary,[...Buff]>}`

type Sum<
    A extends Numerable,
    B extends Numerable> =
    ReverseString<ReverseStringSum<ReverseString<Stringify<A>>,ReverseString<Stringify<B>>>>

Solution by justBadProgrammer #16249

// your answers
type Num = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
type NumMap<T extends unknown[]> = {
  '0': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T],
  '1': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown,],
  '2': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown,],
  '3': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown, unknown,],
  '4': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown, unknown, unknown,],
  '5': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown, unknown, unknown, unknown,],
  '6': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown, unknown, unknown, unknown, unknown,],
  '7': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown, unknown, unknown, unknown, unknown, unknown,],
  '8': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown,],
  '9': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown,],
}
type GetArr<N, T extends unknown[] = []> = N extends Num ? NumMap<T>[N] : []

// 方法一:暴力扩展数组
// 类型生成的元组类型太大,无法表示
// type StringToArr<S extends string, R extends any[] = []> = S extends `${infer F}${infer Rest}` ? StringToArr<Rest, GetArr<F, R>> : R
// type Sum<A extends string | number | bigint, B extends string | number | bigint> = [...StringToArr<`${A}`>, ...StringToArr<`${B}`>] extends any[] 
// ? `${[...StringToArr<`${A}`>, ...StringToArr<`${B}`>]['length']}` : never

// 方法二:逐位相加
type StringToArr<S extends string> = S extends `${infer F}${infer R}` ? [F, ...StringToArr<R>] : []
type ArrToString<A extends any[]> = A extends [infer F extends Num, ...infer R] ? `${F}${ArrToString<R>}` : ''
// 返回一位或者两位的元组,如果是两位,则第一位是进位
type AddTwoNum<A extends Num, B extends Num, Carry extends Num> = [...GetArr<A>, ...GetArr<B>, ...GetArr<Carry>] extends any[]
  ? StringToArr<`${[...GetArr<A>, ...GetArr<B>, ...GetArr<Carry>]['length']}`>
  : ['0']

type AddTwoArr<A extends Num[], B extends Num[], Res extends Num[] = [], Carry extends Num = '0'> =
  A extends [...infer Fa extends Num[], infer La extends Num]
  ? (
    B extends [...infer Fb extends Num[], infer Lb extends Num] // 从两个数组的最后一位开始相加
    ? (
      AddTwoNum<La, Lb, Carry> extends [infer Fc extends Num, infer Lc extends Num, ...infer Rest] // 有进位则进位
      ? AddTwoArr<Fa, Fb, [Lc, ...Res], Fc>
      : AddTwoNum<La, Lb, Carry> extends [infer Fc extends Num, ...infer Rest]
      ? AddTwoArr<Fa, Fb, [Fc, ...Res], '0'> : []
    )
    : (
      // 数组B为空,A存在
      AddTwoNum<La, '0', Carry> extends [infer Fc extends Num, infer Lc extends Num, ...infer Rest]
      ? AddTwoArr<Fa, [], [Lc, ...Res], Fc>
      : AddTwoNum<La, '0', Carry> extends [infer Fc extends Num, ...infer Rest]
      ? AddTwoArr<Fa, [], [Fc, ...Res], '0'> : []
    )
  )
  : (
    // 数组B存在,A为空
    B extends [...infer Fb extends Num[], infer Lb extends Num]
    ? (
      AddTwoNum<'0', Lb, Carry> extends [infer Fc extends Num, infer Lc extends Num, ...infer Rest]
      ? AddTwoArr<[], Fb, [Lc, ...Res], Fc>
      : AddTwoNum<'0', Lb, Carry> extends [infer Fc extends Num, ...infer Rest]
      ? AddTwoArr<[], Fb, [Fc, ...Res], '0'> : []
    )
    // 两个数组都为空时判断是否还需要进位,否则直接返回结果数组
    : Carry extends '0' ? Res
    : (
      AddTwoNum<'0', '0', Carry> extends [infer Fc extends Num, infer Lc extends Num, ...infer Rest]
      ? AddTwoArr<[], [], [Lc, ...Res], Fc>
      : AddTwoNum<'0', '0', Carry> extends [infer Fc extends Num, ...infer Rest]
      ? AddTwoArr<[], [], [Fc, ...Res], '0'> : []
    )
  )

type Sum<A extends string | number | bigint, B extends string | number | bigint> = ArrToString<AddTwoArr<StringToArr<`${A}`>, StringToArr<`${B}`>>>

Solution by fengchunqi #14629