题目要求

实现一个Sum 通过如下测试样例

示例

type Sum<A extends string | number | bigint, B extends string | number | bigint> = string

测试样例

import { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Sum<2, 3>, '5'>>,
  Expect<Equal<Sum<'13', '21'>, '34'>>,
  Expect<Equal<Sum<'328', 7>, '335'>>,
  Expect<Equal<Sum<1_000_000_000_000n, '123'>, '1000000000123'>>,
  Expect<Equal<Sum<9999, 1>, '10000'>>,
  Expect<Equal<Sum<4325234, '39532'>, '4364766'>>,
  Expect<Equal<Sum<728, 0>, '728'>>,
  Expect<Equal<Sum<'0', 213>, '213'>>,
  Expect<Equal<Sum<0, '0'>, '0'>>
]

问题分析

简易版的Sum

使用 解构运算符 和 Tuple 的 length 属性很容易做到

type Computable = string | number | bigint

type NumberToTuple<T extends Computable, R extends any[] = []> = 
  `${T}` extends `${R['length']}` ? R : NumberToTuple<T, [...R, 1]>

type Sum<A extends Computable, B extends Computable> = 
  `${[...NumberToTuple<A>, ...NumberToTuple<B>]['length'] & number}` 

但是对于大数就没有办法了

最终版本

参考大数加法

  1. 反转两个被加数
  2. 对从低到高对每一位做加法然后进位
    • 由于最大情况是 9 + 9 进 1 位,所以只需要考虑进位或者不进位
    • 对计算结果取余,当前位留下余数,并向上进位
  3. 反转计算后的数

反转字符串

递归反转字符串

type Reverse<T extends string> = T extends `${infer L}${infer R}` ? `${Reverse<R>}${L}` : ''

处理进位

type Remaind10<T extends any[]> = T extends [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...infer R]
? {
  number: R['length']
  count: '1'
}
: {
  number: T['length']
  count: ''
}

最后答案

type Computable = string | number | bigint

type NumberToTuple<T extends Computable, R extends any[] = []> = `${T}` extends `${number}`
? `${T}` extends `${R['length']}`
  ? R
  : NumberToTuple<T, [...R, 1]>
: []

type Remaind10<T extends any[]> = T extends [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...infer R]
? {
  number: R['length']
  count: '1'
}
: {
  number: T['length']
  count: ''
}

type Reverse<T extends string> = T extends `${infer L}${infer R}` ? `${Reverse<R>}${L}` : ''

type HalfAdd<A extends Computable, B extends Computable, count extends string = ''> = 
    Remaind10<[...NumberToTuple<A>, ...NumberToTuple<B>, ...count extends '1' ? [1] : []]>

type StrAdd<A extends string, B extends string, count extends string = '0'> =
A extends `${infer AL}${infer AR}`
  ? B extends `${infer BL}${infer BR}`
    ? `${HalfAdd<AL, BL, count>['number'] & number}${StrAdd<AR, BR, HalfAdd<AL, BL, count>['count']>}`
    : `${HalfAdd<AL, count>['number'] & number}${StrAdd<AR, '0', HalfAdd<AL, count>['count']>}`
  : B extends `${infer BL}${infer BR}`
    ? `${HalfAdd<BL, count>['number'] & number}${StrAdd<'', BR, HalfAdd<BL, count>['count']>}`
    : count

type Sum<A extends Computable, B extends Computable> = Reverse<StrAdd<Reverse<`${A}`>, Reverse<`${B}`>>>