题目要求
实现一个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}`
但是对于大数就没有办法了
最终版本
参考大数加法
- 反转两个被加数
- 对从低到高对每一位做加法然后进位
- 由于最大情况是 9 + 9 进 1 位,所以只需要考虑进位或者不进位
- 对计算结果取余,当前位留下余数,并向上进位
- 反转计算后的数
反转字符串
递归反转字符串
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}`>>>