Solution that avoids the need for creating digit dictionaries or matrices. I utilized a Sum type, which I created during the 476 Sum challenge.
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}`>>>;
type MultiplyReverseString<S extends string> = S extends `${infer Head}${infer Tail}`
? `${ReverseString<Tail>}${Head}`
: '';
type MultiplyDigits<
A1 extends number,
A2 extends number,
MultiplyCounter extends unknown[] = [],
Acc extends unknown[][] = [[], []]
> = MultiplyCounter['length'] extends A1
? Acc[0]['length']
: Acc[1]['length'] extends A2
? MultiplyDigits<A1, A2, [unknown, ...MultiplyCounter], [[...Acc[0], ...Acc[1]], []]>
: MultiplyDigits<A1, A2, MultiplyCounter, [Acc[0], [unknown, ...Acc[1]]]>;
type CreateMultiplyComponent<A extends string, B extends number, Rest extends number = 0> =
A extends `${infer Head extends number}${infer Tail}`
? `${Sum<MultiplyDigits<B, Head>, Rest>}` extends `${infer SumRest extends number}${infer Result extends number}`
? `${Result}${CreateMultiplyComponent<Tail, B, SumRest>}`
: `${Sum<MultiplyDigits<B, Head>, Rest>}${CreateMultiplyComponent<Tail, B, 0>}`
: Rest extends 0 ? '' : `${Rest}`;
type IsAOrBZero<A extends string, B extends string> = '0' extends A | B ? true : false;
type MultiplyHelper<
A extends string,
B extends string,
Zeros extends string = ''
> = B extends `${infer Head extends number}${infer Tail}`
? Sum<
ReverseString<`${Zeros}${CreateMultiplyComponent<A, Head>}`>,
MultiplyHelper<A, Tail, `${Zeros}0`>
>
: 0;
type Multiply<A extends string | number | bigint, B extends string | number | bigint> =
IsAOrBZero<`${A}`, `${B}`> extends true
? '0'
: MultiplyHelper<MultiplyReverseString<`${A}`>, MultiplyReverseString<`${B}`>>;
Solution by user1808 #32694
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 MinusOne<A extends number, P extends 1[] = [1], Cnt extends 1[] = []> = A extends P['length'] ? Cnt['length'] : MinusOne<A, [...P, 1], [...Cnt, 1]>
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
type Time<A extends string, Times extends number, P extends 1[] = [1], Result extends string = A> = Times extends P['length'] ? Result :Time<A, Times, [...P, 1], Sum<Result, A>>
type TimeWithZero<A extends string, Times extends number> = Times extends 0 ? "0" : Time<A, Times>
type RecursiveMultiply<A extends string, B extends string, Result extends string = "0"> =
A extends "" ? Result :
A extends `${infer AFirst extends number}${infer ARest}` ?
AFirst extends 0 ?
RecursiveMultiply<ARest, B, Result>: Time<B, AFirst> extends `${infer NewResult extends string}` ?
RecursiveMultiply<ARest, B, Sum<Result, AppendZeros<NewResult, StringSize<ARest>>>>
: never
: Result
type Multiply<A extends string | number | bigint, B extends string | number | bigint> = `${B}` extends "0" ? "0" : RecursiveMultiply<`${A}` ,`${B}`>
Solution by john-cremit #32496
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 Matrix<
A extends number,
B extends number,
C extends 0[] = []
> = C["length"] extends B ? [] : [...Tuple<A>, ...Matrix<A, B, [...C, 0]>];
type SingleMultiply<
A extends number,
B extends number,
Carry extends number = 0
> = [...Matrix<A, B>, ...Tuple<Carry>]["length"];
type SingleMultiplyLong<
S extends number,
L extends string,
Carry extends number = 0
> = L extends `${infer First extends number}${infer Rest}`
? `${SingleMultiply<S, First, Carry> &
number}` extends `${infer NewCarry extends number}${infer Sum extends number}`
? `${Sum}${SingleMultiplyLong<S, Rest, NewCarry>}`
: `${SingleMultiply<S, First, Carry> & number}${SingleMultiplyLong<
S,
Rest,
0
>}`
: Carry extends 0
? ""
: `${Carry}`;
type LeadingZero<N extends number, C extends 0[] = []> = C["length"] extends N
? ""
: `0${LeadingZero<N, [...C, 0]>}`;
type MultiplyReversedString<
A extends string,
B extends string,
C extends 0[] = []
> = A extends `${infer FirstA extends number}${infer RestA}`
? SumReversedString<
`${LeadingZero<C["length"]>}${SingleMultiplyLong<FirstA, B>}`,
MultiplyReversedString<RestA, B, [...C, 0]>
>
: "";
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint
> = "0" extends `${A}` | `${B}`
? "0"
: ReverseString<
MultiplyReversedString<ReverseString<`${A}`>, ReverseString<`${B}`>>
>;
Solution by vangie #32393
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}`>>>>;
type MulMap = [
['0', '0', '0', '0', '0', '0', '0', '0', '0', '0'],
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
['0', '2', '4', '6', '8', '01', '21', '41', '61', '81'],
['0', '3', '6', '9', '21', '51', '81', '12', '42', '72'],
['0', '4', '8', '21', '61', '02', '42', '82', '23', '63'],
['0', '5', '01', '51', '02', '52', '03', '53', '04', '54'],
['0', '6', '21', '81', '42', '03', '63', '24', '84', '45'],
['0', '7', '41', '12', '82', '53', '24', '94', '65', '36'],
['0', '8', '61', '42', '23', '04', '84', '65', '46', '27'],
['0', '9', '81', '72', '63', '54', '45', '36', '27', '18']
];
type GetMul<X extends string, Y extends string> = X extends keyof MulMap
? Y extends keyof MulMap[X]
? MulMap[X][Y]
: '0'
: '0';
type MulOne<
X extends string,
Y extends string,
O extends string = ''
> = X extends '0'
? '0'
: X extends `${infer E}${infer R}`
? SumString<`${O}${GetMul<E, Y>}`, MulOne<R, Y, `0${O}`>>
: '0';
type MulAll<
X extends string,
Y extends string,
O extends string = ''
> = X extends '0'
? '0'
: Y extends '0'
? '0'
: Y extends `${infer E}${infer R}`
? SumString<`${O}${MulOne<X, E>}`, MulAll<X, R, `0${O}`>>
: '0';
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint
> = Reverse<MulAll<Reverse<Format<`${A}`>>, Reverse<Format<`${B}`>>>>;
type T = Multiply<'43423', '321543'>;
Solution by Royce-DaDaDa #29812
// Utils
type Reverse<S extends string> = S extends `${infer F}${infer R}`
? `${Reverse<R>}${F}`
: S;
// Sum helpers
type SumMod10 = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
[2, 3, 4, 5, 6, 7, 8, 9, 0, 1],
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2],
[4, 5, 6, 7, 8, 9, 0, 1, 2, 3],
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4],
[6, 7, 8, 9, 0, 1, 2, 3, 4, 5],
[7, 8, 9, 0, 1, 2, 3, 4, 5, 6],
[8, 9, 0, 1, 2, 3, 4, 5, 6, 7],
[9, 0, 1, 2, 3, 4, 5, 6, 7, 8]
];
type SumCarryOver = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];
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}`
? `${SumMod10[SumMod10[AF][BF]][C]}${StringSum<
AR,
BR,
SumMod10[SumCarryOver[AF][BF]][SumCarryOver[SumMod10[AF][BF]][C]]
>}`
: `${SumMod10[AF][C]}${SumCarryOver[AF][C] extends 1
? StringSum<AR, '', 1>
: AR}`
: B extends `${infer BF extends number}${infer BR}`
? `${SumMod10[BF][C]}${SumCarryOver[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}`>>>;
// Multiply helpers
type MultiplyMod10 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 2, 4, 6, 8, 0, 2, 4, 6, 8],
[0, 3, 6, 9, 2, 5, 8, 1, 4, 7],
[0, 4, 8, 2, 6, 0, 4, 8, 2, 6],
[0, 5, 0, 5, 0, 5, 0, 5, 0, 5],
[0, 6, 2, 8, 4, 0, 6, 2, 8, 4],
[0, 7, 4, 1, 8, 5, 2, 9, 6, 3],
[0, 8, 6, 4, 2, 0, 8, 6, 4, 2],
[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
];
type MultiplyCarryOver = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1, 1, 2, 2, 2],
[0, 0, 0, 1, 1, 2, 2, 2, 3, 3],
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4],
[0, 0, 1, 1, 2, 3, 3, 4, 8, 5],
[0, 0, 1, 2, 2, 3, 4, 4, 5, 6],
[0, 0, 1, 2, 3, 4, 4, 5, 6, 7],
[0, 0, 1, 2, 3, 4, 5, 6, 7, 8]
];
type MultiplyWithZero<T> = '0' extends T ? true : false;
type TrailingZeros<N extends number, I extends 1[] = []> = I['length'] extends N
? ''
: `0${TrailingZeros<N, [...I, 1]>}`;
type MultiplyWithDigit<
S extends string,
D extends number,
C extends number = 0
> = S extends `${infer F extends number}${infer R}`
? `${SumMod10[MultiplyMod10[F][D]][C]}${MultiplyWithDigit<
R,
D,
SumMod10[MultiplyCarryOver[F][D]][SumCarryOver[MultiplyMod10[F][D]][C]]
>}`
: C extends 0
? ''
: `${C}`;
type StringMultiply<
A extends string,
B extends string,
S extends string = '0',
I extends 1[] = []
> = B extends `${infer F extends number}${infer R}`
? StringMultiply<
A,
R,
Sum<
`${Reverse<MultiplyWithDigit<A, F>>}${TrailingZeros<I['length']>}`,
S
>,
[...I, 1]
>
: S;
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint
> = MultiplyWithZero<`${A}` | `${B}`> extends true
? '0'
: StringMultiply<Reverse<`${A}`>, Reverse<`${B}`>>;
Solution by JohnLi1999 #27482
/**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}`> :
Number<_Result> extends 0/*去0*/ ? `` : _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 | bigint> = T extends `0${infer R}`/*去0*/ ? Number<R> : T extends `${infer N extends number | bigint}` ? N : 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 DigitMultiply<T extends string | number | bigint, U extends Digit, _Counter extends 1[] = [], _Result extends string = `0`> = _Counter[`length`] extends U ? _Result : DigitMultiply<T, U, [..._Counter, 1], Sum<_Result, T>>;
/**x10^n */
type TenPow<T extends string | number | bigint, N extends number, _Counter extends 1[] = []> = _Counter[`length`] extends N ? T : `${TenPow<T, N, [..._Counter, 1]>}0`;
/**加法器(自然数) */
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}`>;
/**乘法器(自然数) */
type Multiply<A extends string | number | bigint, B extends string | number | bigint, _CarryCounter extends 1[] = [], _Result extends string = `0`> = B extends `` ? _Result : //return
Multiply<A, DigitRest<B>, [..._CarryCounter, 1], Sum<_Result, TenPow<DigitMultiply<A, DigitFirst<B>>, _CarryCounter[`length`]>>>;
// 123 * 12345 ==> (123 * 5)
// ==> + (123 * 40)
// ==> + (123 * 300)
// ==> + (123 * 2000)
// ==> + (123 * 10000)
Solution by E-uler #25531
// handles arbitrarily large numbers
type IntADT = number | string | bigint;
type DigitLUT = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
type Digit = DigitLUT[number];
type Multiply<
A extends IntADT,
B extends IntADT,
B_TUPLE extends Digit[] = IntToTuple<B>,
OUTPUT extends Digit[] = [],
OFFSET extends number = 0,
B_LSD extends Digit = B_TUPLE extends [] ? '0' : Last<B_TUPLE, Digit>,
MUL extends IntADT = MultiplyByDigit<A, B_LSD>,
MUL_LSHIFT extends IntADT = LeftShift<MUL, OFFSET>,
NEXT extends Digit[] = $sum<never, MUL_LSHIFT, OUTPUT>,
IS_ANY_ZERO extends boolean = Any<[Equal<`${A}`, '0'>, Equal<`${B}`, '0'>]>,
RESULT extends IntADT = IS_ANY_ZERO extends true ? '0'
: B_TUPLE extends []
? Join<OUTPUT>
: Multiply<A, B, Pop<B_TUPLE>, NEXT, Add<OFFSET, 1>>,
> = RESULT;
type MultiplyByDigit<
A extends IntADT,
B extends Digit,
A_TUPLE extends Digit[] = IntToTuple<A>,
OUTPUT extends Digit[] = [],
CARRY_IN extends Digit = '0',
A_LSD extends Digit = A_TUPLE extends [] ? '0' : Last<A_TUPLE, Digit>,
MUL extends number = Add<MultiplyDigits<A_LSD, B>, CARRY_IN>,
CURR extends Digit = LSD<MUL>,
CARRY_OUT extends Digit = `${MUL}` extends CURR ? '0' : MSD<MUL>,
NEXT extends Digit[] = Unshift<OUTPUT, CURR>,
IS_ANY_ZERO extends boolean = Any<[Equal<`${A}`, '0'>, Equal<B, '0'>]>,
RESULT extends IntADT = IS_ANY_ZERO extends true ? '0'
: A_TUPLE extends []
? CARRY_IN extends '0' ? Join<OUTPUT> : Join<Unshift<OUTPUT, CARRY_IN>>
: MultiplyByDigit<A, B, Pop<A_TUPLE>, NEXT, CARRY_OUT>
> = RESULT;
type MultiplyDigits<
A extends Digit,
B extends Digit,
X extends number = `${A}` extends `${infer X extends number}` ? X : 0,
Y extends number = `${B}` extends `${infer Y extends number}` ? Y : 0,
OUTPUT extends unknown[] = [],
RESULT extends IntADT = Y extends 0
? `${OUTPUT["length"]}`
: MultiplyDigits<A, B, X, Subtract<Y, 1>, Concat<OUTPUT, Repeat<X>>>
> = RESULT;
type multiply_digits_tests = [
Expect<Equal<MultiplyDigits<'0', '0'>, '0'>>,
Expect<Equal<MultiplyDigits<'0', '9'>, '0'>>,
Expect<Equal<MultiplyDigits<'1', '1'>, '1'>>,
Expect<Equal<MultiplyDigits<'1', '5'>, '5'>>,
Expect<Equal<MultiplyDigits<'5', '1'>, '5'>>,
Expect<Equal<MultiplyDigits<'6', '6'>, '36'>>,
Expect<Equal<MultiplyDigits<'8', '9'>, '72'>>,
];
type multiply_by_digit_tests = [
Expect<Equal<MultiplyByDigit<'0', '0'>, '0'>>,
Expect<Equal<MultiplyByDigit<1, '2'>, '2'>>,
Expect<Equal<MultiplyByDigit<999, '0'>, '0'>>,
Expect<Equal<MultiplyByDigit<'999', '1'>, '999'>>,
Expect<Equal<MultiplyByDigit<13, '2'>, '26'>>,
Expect<Equal<MultiplyByDigit<999, '9'>, '8991'>>,
Expect<Equal<MultiplyByDigit<'1923', '9'>, '17307'>>,
Expect<Equal<MultiplyByDigit<123456789, '9'>, '1111111101'>>,
];
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;
/** @returns Digit */
type MSD<N extends IntADT> =
`${N}` extends `${infer H extends Digit}${string}` ? H : '0';
/** @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;
/** @returns string */
type LeftShift<
T extends IntADT,
N extends number = 1,
OUTPUT extends string = `${T}`,
NEXT extends string = `${OUTPUT}0`,
RESULT extends IntADT = N extends 0 ? OUTPUT : LeftShift<T, Subtract<N, 1>, NEXT>,
> = RESULT;
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 Any<T extends boolean[]> =
T extends [infer B, ...infer Rest extends boolean[]]
? B extends true ? true : Any<Rest>
: false;
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 Last<T extends U[], U = any> =
T extends [...infer _, infer P extends U] ? P : never;
type Pop<T extends unknown[], N extends number = 1> =
N extends 0 ? T
: T extends [...infer Rest, infer _]
? Pop<Rest, Subtract<N, 1>>
: [];
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 #22399
type IsIncludesZero<T> = [Extract<T, 0 | '0'>] extends [never] ? false : true
type MultiplyWithSmallNumber<
A extends string | number | bigint,
B extends string | number | bigint,
AC extends unknown[] = [],
T extends string = '0',
> = `${A}` extends `${infer X extends number}`
? X extends AC['length']
? T
: MultiplyWithSmallNumber<A, B, [unknown, ...AC], Sum<T, B>>
: never
type MultiplyNoZero<
A extends string | number | bigint,
B extends string | number | bigint,
T extends string = '0',
Add extends string = '',
> = ReverseString<`${A}`> extends `${infer F extends number}${infer R}`
? MultiplyNoZero<ReverseString<R>, B, Sum<`${MultiplyWithSmallNumber<F, B>}${Add}`, T>, `${Add}0`>
: T
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint,
> = IsIncludesZero<A | B> extends true ? '0' : MultiplyNoZero<A, B>
Solution by thanhhtse04588 #22284
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 }`>
// 476
// =============================================================================
// Present
type _ShiftZero<T extends string> = T extends `0${ infer Rest }` ? (Rest extends '' ? '0' : _ShiftZero<Rest>) : T
type _TwoSingleDigitMultiply<
A extends _DigitString,
B extends _DigitString,
_Acc extends string = '0',
_Times extends 0[] = [],
_A extends _DigitString = _ShiftZero<A>,
_B extends _DigitString = _ShiftZero<B>,
> = `${ _Times['length'] }` extends _B
? _Acc extends `${ infer Tens }${ infer Single }`
? Single extends ''
? { carry: '0', digit: _Acc & _DigitString }
: { carry: Tens & _DigitString, digit: Single & _DigitString }
: never
: _TwoSingleDigitMultiply<_A, _B, Sum<_A, _Acc>, [ ..._Times, 0 ]>
type _OnlyOneSingleDigitMultiply<
A extends string,
B extends _DigitString,
_Carry extends _DigitString = '0',
_AL extends { rest: string, last: _DigitString } = _GetLast<A>,
_Step extends { carry: _DigitString, digit: _DigitString } = _TwoSingleDigitMultiply<_AL['last'], B, _Carry>,
_Result extends string = '',
> = _AL['rest'] extends ''
? `${ _Step['carry'] extends '0' ? '' : _Step['carry'] }${ _Step['digit'] }`
: `${ _OnlyOneSingleDigitMultiply<_AL['rest'], B, _Step['carry']> }${ _Step['digit'] }`
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint,
_Acc extends string = '0',
_Zeroes extends string = '',
_BL extends { rest: string, last: _DigitString } = _GetLast<B>,
> = _BL['rest'] extends ''
? _ShiftZero<Sum<`${ _Acc }`, _OnlyOneSingleDigitMultiply<`${ A }${ _Zeroes }`, _BL['last']>>>
: Multiply<A, _BL['rest'], Sum<`${ _Acc }`, _OnlyOneSingleDigitMultiply<`${ A }${ _Zeroes }`, _BL['last']>>, `${ _Zeroes }0`>
Solution by lvjiaxuan #22281
// reverse a string
type Reverse<S extends string> = S extends `${infer F}${infer Rest}` ? `${Reverse<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}`
? Reverse<`${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> = Reverse<SumReversedString<Reverse<`${A}`>, Reverse<`${B}`>>>
// ----Above is from Sum----
type MultiplicationTable = {
'00': 0, '01': 0, '02': 0, '03': 0, '04': 0, '05': 0, '06': 0, '07': 0, '08': 0, '09': 0,
'11': 1, '12': 2, '13': 3, '14': 4, '15': 5, '16': 6, '17': 7, '18': 8, '19': 9,
'22': 4, '23': 6, '24': 8, '25': 10, '26': 12, '27': 14, '28': 16, '29': 18,
'33': 9, '34': 12, '35': 15, '36': 18, '37': 21, '38': 24, '39': 27,
'44': 16, '45': 20, '46': 24, '47': 28, '48': 32, '49': 36,
'55': 25, '56': 30, '57': 35, '58': 40, '59': 45,
'66': 36, '67': 42, '68': 48, '69': 54,
'77': 49, '78': 56, '79': 63,
'88': 64, '89': 72,
'99': 81
}
// sort digits A and B, ouptut a string with the smaller one left and bigger one right
type SortDigits<A extends number | string, B extends number | string> = '0123456789' extends `${any}${A}${any}${B}${any}` ? `${A}${B}` : `${B}${A}`
// multiply two digits A and B
type MultiDigits<A extends number | string, B extends number | string> = MultiplicationTable[SortDigits<A, B> & keyof MultiplicationTable]
// append extra zero string right to a number. if the number is zero, just output '0'.
type WithZeros<N extends number, Z extends string> = N extends 0 ? '0' : `${N}${Z}`
// sub step of MultiplyReversedString, where A is a digit but B is a number, and iterate B
type MultiplyReversedString_2<A extends string, B extends string, _Zeros extends string = ''> =
B extends `${infer BF extends number}${infer BRest}`
? Reverse<Sum<WithZeros<MultiDigits<A, BF>, _Zeros>, Reverse<MultiplyReversedString_2<A, BRest, `${_Zeros}0`>>>>
: '0'
// sub step of MultiplyReversedString, where A and B are numbers, and iterate A
type MultiplyReversedString_1<A extends string, B extends string, _Zeros extends string = ''> =
A extends `${infer AF}${infer ARest}`
? Reverse<Sum<Reverse<MultiplyReversedString_2<AF, B, _Zeros>>, Reverse<MultiplyReversedString_1<ARest, B, `${_Zeros}0`>>>>
: '0'
// multiply two number A and B in reversed string format
type MultiplyReversedString<A extends string, B extends string> = MultiplyReversedString_1<A, B>
type Multiply<A extends string | number | bigint, B extends string | number | bigint> = Reverse<MultiplyReversedString<Reverse<`${A}`>, Reverse<`${B}`>>>
Solution by zhaoyao91 #22230
// your answers
namespace SumChallenge {
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 较小的两个数相加
export 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]>;
// 判断两个数字的大小
export 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]>;
// 反转字符串
export type ReverseString<S extends string> = S extends `${infer F}${infer R}`
? `${ReverseString<R>}${F}`
: "";
// 获取字符串长度
export type GetStringLength<
S extends string,
I extends 0[] = []
> = S extends `${string}${infer R}`
? GetStringLength<R, [0, ...I]>
: I["length"];
export 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}`;
export 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}`>>
>;
// 0 ~ 9 范围内的两个数相加, [a, b] a表示剩余数,b表示进位数
}
namespace MutiplyChallenge {
// 0. 生成一个保存每一相位的值的数组
type InitialZeroArr<
N extends number,
Res extends string[] = []
> = Res["length"] extends N ? Res : InitialZeroArr<N, [...Res, "0"]>;
type LitterNumberMul<
Base extends string,
B extends string,
I extends 0[] = [],
Res extends string = "0"
> = `${I["length"]}` extends B
? Res
: LitterNumberMul<Base, B, [0, ...I], SumChallenge.Sum<Base, Res>>;
type StringToRevArr<S extends string> = S extends `${infer F}${infer R}` ? [...StringToRevArr<R>, F] : [];
type ChangeArrByIndex<Arr extends string[], Tindex extends number, Value, I extends 0[] = []> =
Arr extends [infer F, ...infer R extends string[]] ?
I["length"] extends Tindex ? [Value, ...R]
: [F, ...ChangeArrByIndex<R, Tindex, Value, [0, ...I]>]
: [];
type GetArrValueByIndex<Arr extends string[], Index extends number, I extends 0[] = []> =
Arr extends [infer F, ...infer R extends string[]] ?
I["length"] extends Index ?
F
: GetArrValueByIndex<R, Index, [0, ...I]>
: never;
type MutiplyFirst<A extends string[], B extends string[], Res extends string[] = [], I1 extends 0[] = [], I2 extends 0[] = [], ResI extends number = SumChallenge.Add<I1["length"], I2["length"]>> =
I2["length"] extends B["length"] ?
I1["length"] extends A["length"] ?
Res
: MutiplyFirst<A, B, Res, [0, ...I1], []>
: MutiplyFirst<A, B,
ChangeArrByIndex<Res, ResI, SumChallenge.ReverseString<SumChallenge.Sum<SumChallenge.ReverseString<Res[ResI]>, LitterNumberMul<A[I1["length"]], B[I2["length"]]>>>>
, I1, [0, ...I2]>;
type MutiplySeconde<C extends string[], I extends 0[] = [], JW extends string = "0", Res extends string[] = []> =
I["length"] extends C["length"] ?
Res
: SumChallenge.ReverseString<SumChallenge.Sum<SumChallenge.ReverseString<C[I["length"]]>, SumChallenge.ReverseString<JW>>> extends `${infer F}${infer R}` ?
R extends "" ?
MutiplySeconde<C, [0, ...I], "0", [...Res, F]>
: MutiplySeconde<C, [0, ...I], R, [...Res, F]>
: never;
// 拼接字符串
type MutiplyThree<C extends string[]> = C extends [infer F extends string, ...infer R extends string[]] ?
`${MutiplyThree<R>}${F}`
: "";
// 去除前导0
type MultiplyFour<C extends string> = C extends `0${infer R}` ? MultiplyFour<R> : C extends "" ? "0" : C;
export type Multiply<A extends string | number | bigint, B extends string | number | bigint> = MultiplyFour<MutiplyThree<MutiplySeconde<MutiplyFirst<StringToRevArr<`${A}`>, StringToRevArr<`${B}`>, InitialZeroArr<30>>>>>;
}
type Multiply<A extends string | number | bigint, B extends string | number | bigint> = MutiplyChallenge.Multiply<A, B>;
Solution by acwink #22225
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 GetSLast1<T extends string | number | bigint> =
`${T}` extends `${infer A}${infer B}` ? stringToNumber<A> : "";
type GetSLast<
T extends string | number | bigint,
B extends string | number | bigint
> = [GetSLast1<T>, GetSLast1<B>];
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>>>;
type PushZero<B extends string, T extends Array<never>> = T extends [
infer A,
...infer C extends Array<never>
]
? PushZero<`${B}0`, C>
: B;
type Multiply2<
P extends string | number | bigint,
T extends string | number | bigint,
G extends Array<never> = [],
Result extends string = ""
> = P extends 0
? "0"
: P extends G["length"]
? Result
: Multiply2<P, T, [never, ...G], Sum<T, Result>>;
type GetOtherString<
G extends string | number | bigint,
C extends string | number | bigint
> = G extends `${C}${infer R}` ? R : G;
type Multiply1<
A extends string | number | bigint,
B extends string | number | bigint,
Index extends Array<never> = [],
Result extends string = ""
> = A extends ""
? Result
: ["0"] extends [`${A}` | `${B}`]
? "0"
: Multiply2<GetSLast1<A>, B> extends `${infer C}`
? Multiply1<
GetOtherString<A, GetSLast1<A>>,
B,
[never, ...Index],
Sum<PushZero<C, Index>, Result>
>
: never;
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint
> = Multiply1<Reverse<A>, B>;
Solution by so11y #21648
type NumberWithinTen<
T extends string | number,
R extends unknown[] = []
> = `${R['length']}` extends `${T}` ? R : NumberWithinTen<T, [unknown, ...R]>
type StringToCharArray<T extends string> = T extends `${infer A}${infer B}`
? [A, ...StringToCharArray<B>]
: []
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>>
type MultiplyWithinTen<
A extends unknown[],
B extends unknown[]
> = B['length'] extends 0 ? [] : [...A, ...MultiplyWithinTen<A, Shift<B>>]
type MultiplyUnit<
A extends unknown[] | undefined,
B extends unknown[] | undefined,
Carry extends unknown[] = []
> = A extends unknown[]
? B extends unknown[]
? [...Carry, ...MultiplyWithinTen<A, B>]
: Carry['length'] extends 0
? unknown
: Carry
: Carry['length'] extends 0
? unknown
: Carry
type BasicMultiply<
A extends string | number | bigint,
B extends string | number | bigint,
C extends unknown[] = [],
AInNumberArray extends unknown[][] = Reverse<StringToNumberArray<`${A}`>>,
BInNumber extends unknown[] = NumberWithinTen<`${B}`>,
UnitResult extends string = MultiplyUnit<
AInNumberArray[0],
BInNumber,
C
> extends unknown[]
? // @ts-ignore
`${MultiplyUnit<AInNumberArray[0], BInNumber, C>['length']}`
: ''
> = UnitResult extends `${infer MU1}${infer MU2}`
? `${BasicMultiply<
A,
B,
MU2 extends '' ? [] : NumberWithinTen<MU1>,
Shift<AInNumberArray>,
BInNumber
>}${MU2 extends '' ? MU1 : MU2}`
: UnitResult
type SumProduct<
Product extends unknown[],
Result extends string = '0',
LeftZero extends string = ''
> = Product extends [infer A, ...infer B]
? // @ts-ignore
SumProduct<B, Sum<Result, `${A}${LeftZero}`>, `${LeftZero}0`>
: Result
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint,
BInCharArray extends string[] = Reverse<StringToCharArray<`${B}`>>,
Product extends string[] = []
> = BInCharArray['length'] extends 0
? SumProduct<Product>
: Multiply<
A,
B,
Shift<BInCharArray>,
[...Product, BasicMultiply<A, BInCharArray[0]>]
>
Solution by theoolee #19951
type Numerable = string | number | bigint;
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 Digit = keyof DigitMap;
type Number = Digit[];
type Val<D extends Digit> = DigitMap[D];
type Inc<N extends Digit> = `${[1, ...Val<N>]["length"] & number}` & Digit;
type GetNumber<N extends Numerable> =
`${N}` extends `${infer D extends Digit}${infer S}`
? S extends ""
? [D]
: [D, ...GetNumber<S>]
: never;
type NumberToString<N extends Number, I = false> = N extends [
infer F extends Digit,
...infer R extends Number
]
? `${F}${NumberToString<R, true>}`
: I extends true
? ""
: "0";
type SplitCarry<
N extends number,
S = `${N}`
> = S extends `${infer C extends Digit}${infer V extends Digit}`
? [C, V]
: S extends Digit
? ["0", S]
: never;
type DigitSum<
A extends Digit,
B extends Digit,
Carry extends Digit = "0"
> = SplitCarry<[...Val<A>, ...Val<B>, ...Val<Carry>]["length"] & number>;
type RemoveLeadingZeros<N extends Number> = N extends [
infer F extends Digit,
...infer R extends Number
]
? R extends []
? [F]
: F extends "0"
? RemoveLeadingZeros<R>
: N
: [];
type Pad<N extends Number> = N extends [] ? ["0"] : N;
type NumberSum<
A extends Number,
B extends Number,
Carry extends Digit = "0"
> = [A, B] extends [["0"] | [], ["0"] | []]
? Carry extends "0"
? []
: [Carry]
: [Pad<A>, Pad<B>] extends [
[...infer RA extends Number, infer NA extends Digit],
[...infer RB extends Number, infer NB extends Digit]
]
? DigitSum<NA, NB, Carry> extends [infer Carry extends Digit, infer N]
? [...NumberSum<RA, RB, Carry>, N]
: never
: never;
type DigitMultiply<
A extends Digit,
B extends Digit,
Carry extends Digit = "0",
Sum extends 1[] = Val<A>,
Count extends Digit = "1"
> = [A, B] extends ["0", Digit] | [Digit, "0"]
? SplitCarry<Val<Carry>["length"]>
: Count extends B
? SplitCarry<[...Sum, ...Val<Carry>]["length"] & number>
: DigitMultiply<A, B, Carry, [...Sum, ...Val<A>], Inc<Count>>;
type NumberByDigitMultiply<
A extends Number,
B extends Digit,
Carry extends Digit = "0"
> = B extends "0"
? Carry extends "0"
? []
: [Carry]
: B extends "1"
? NumberSum<A, [Carry]>
: A extends []
? Carry extends "0"
? []
: [Carry]
: A extends [...infer RA extends Number, infer NA extends Digit]
? DigitMultiply<NA, B, Carry> extends [infer Carry extends Digit, infer N]
? [...NumberByDigitMultiply<RA, B, Carry>, N]
: never
: never;
type NumberMultiply<
A extends Number,
B extends Number,
Sum extends Number = [],
Zeros extends "0"[] = []
> = B extends [...infer R extends Number, infer N extends Digit]
? NumberMultiply<
A,
R,
NumberSum<Sum, NumberByDigitMultiply<[...A, ...Zeros], N>>,
["0", ...Zeros]
>
: Sum;
type Sum<A extends Numerable, B extends Numerable> = NumberToString<
RemoveLeadingZeros<NumberSum<GetNumber<A>, GetNumber<B>>>
>;
type Multiply<A extends Numerable, B extends Numerable> = NumberToString<
RemoveLeadingZeros<NumberMultiply<GetNumber<A>, GetNumber<B>>>
>;
Solution by BulatDashiev #17016
// 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>>
type MinusOne<T extends number, Result extends 0[] = NumberToTuple<T>> = Result extends [infer F, ...infer R]
? R['length']
: 0
/**
* SingleMultiply<1, 2> // 2
* SingleMultiply<4, 8> // 32
* SingleMultiply<0, 1> // 0
*/
type SingleMultiply<
T extends number,
D extends number,
C extends number = D,
Result extends unknown[] = []
> = D extends 0
? 0
: C extends 0
? Result['length'] & number
: SingleMultiply<T, D, MinusOne<C>, [
...NumberToTuple<T>,
...Result
]>
/**
* ArrayMul<[3, 2, 1], 1> // '321'
* ArrayMul<[1, 2], 2> // '24'
*/
type ArrayMul<
A extends number[],
B extends number,
C extends number = 0,
Result extends string = '',
AL extends number = Pop<A>
> = A extends []
? C extends 0 ? Result : `${C}${Result}`
: ArrayMul<GetRest<A>, B, GetTens<SingleSum<C, SingleMultiply<AL, B>>>, `${GetDigit<SingleSum<C, SingleMultiply<AL, B>>>}${Result}`>
type EachSum<T, Result extends string = ''> = T extends [infer F extends string, ...infer R]
? EachSum<R, Sum<F, Result>>
: Result
type Multiply<
A extends ParamType,
B extends ParamType,
SA extends number[] = Split<A>,
SB extends number[] = Split<B>,
Result extends string[] = [],
Default extends string = '',
SBL extends number = Pop<SB>
> = Equal<`${A}`, '0'> extends true
? '0'
: Equal<`${B}`, '0'> extends true
? '0'
: SB extends []
? EachSum<Result>
: Multiply<never, never, SA, GetRest<SB>, [ArrayMul<SA, SBL, 0, Default>, ...Result], `0${Default}`>
// 123 * 321
// 123 * 1 => 123
// 123 * 2 * 10 => 2460
// 123 * 3 * 100 => 36900
// => 123 + 2460 + 36900
Solution by humandetail #16659
// 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 Trim0<
S extends string> =
S extends `${0}${infer R}`
? R extends ''
? '0'
: Trim0<R>
: S ;
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>>>> ;
type OneDigitMultiply<
A extends Numerable,
B extends keyof Dictionary,
T extends readonly any[]=[],
Total extends Numerable = '0' > =
B extends `${T['length']}`
? Total
: OneDigitMultiply<A,B,[...T,any],Sum<Total,A>> ;
type ReverseMultiply<
A extends Numerable,
B extends Numerable > =
`${B}` extends `${infer R extends keyof Dictionary}${infer U extends string}`
? Sum<OneDigitMultiply<A,R>,`${ReverseMultiply<A,U>}0`>
: '' ;
type Multiply<
A extends Numerable,
B extends Numerable > =
Trim0<ReverseMultiply<A,ReverseString<Stringify<B>>>> ;
Solution by justBadProgrammer #16251
/* utils */
type Get<T, K> = K extends keyof T ? T[K] : never;
type AsStr<T> = T extends string ? T : never;
type Reverse<S> = S extends `${infer First}${infer Rest}`
? `${Reverse<Rest>}${First}`
: '';
type Head<S> = S extends `${infer First}${string}` ? First : never;
type Tail<S> = S extends `${string}${infer Rest}` ? Rest : never;
type Replace<S, C extends string> = S extends `${string}${infer Rest}`
? `${C}${Replace<Rest, C>}`
: '';
type Rotate<S> = `${Tail<S>}${Head<S>}`;
type Zip<From, To> = From extends `${infer First}${infer Rest}`
? Record<First, Head<To>> & Zip<Rest, Tail<To>>
: {};
/* digits */
type Digits = '0123456789';
type Zero = Head<Digits>;
type One = Head<Tail<Digits>>;
/* helpers */
type GenerateAdd<
To,
Current = Digits,
> = Current extends `${infer First}${infer Rest}`
? Record<First, Zip<Digits, To>> & GenerateAdd<Rotate<To>, Rest>
: {};
type InnerAdd = GenerateAdd<Digits>;
type Add<A, B> = AsStr<Get<Get<InnerAdd, A>, B>>;
type GenerateCarry<
To,
Current = Digits,
> = Current extends `${infer First}${infer Rest}`
? Record<First, Zip<Digits, To>> & GenerateCarry<`${Tail<To>}${One}`, Rest>
: {};
type CarryWithZero = GenerateCarry<Replace<Digits, Zero>>;
type CarryWithOne = GenerateCarry<`${Tail<Replace<Digits, Zero>>}${One}`>;
type Carry<A, B, C> = C extends Zero
? AsStr<Get<Get<CarryWithZero, A>, B>>
: AsStr<Get<Get<CarryWithOne, A>, B>>;
/* sum main */
// type Sum<
// A extends string | number | bigint,
// B extends string | number | bigint,
// > = Reverse<InnerSum<Reverse<`${A}`>, Reverse<`${B}`>>>;
type InnerSum<
A extends string,
B extends string,
C extends string = Zero,
> = A extends `${infer FirstA}${infer RestA}`
? B extends `${infer FirstB}${infer RestB}`
? `${Add<Add<FirstA, FirstB>, C>}${InnerSum<
RestA,
RestB,
Carry<FirstA, FirstB, C>
>}`
: InnerSum<A, C>
: B extends ''
? C extends Zero
? ''
: C
: InnerSum<B, C>;
/* multiply utils */
type ZipArr<From, ToArr> = ToArr extends [infer First, ...infer Rest]
? Record<Head<From>, First> & ZipArr<Tail<From>, Rest>
: {};
type ToArr<S> = S extends `${infer First}${infer Rest}`
? [First, ...ToArr<Rest>]
: [];
/* multiply helpers */
type DigitArr = ToArr<Digits>;
type AddDigitArr<Arr> = {
[Key in keyof Arr]: InnerSum<AsStr<Arr[Key]>, Get<DigitArr, Key>>;
};
type GenerateMulTable<
ToArr,
Current = Digits,
> = Current extends `${infer First}${infer Rest}`
? Record<First, ZipArr<Digits, ToArr>> &
GenerateMulTable<AddDigitArr<ToArr>, Rest>
: {};
type InnerMulTable = GenerateMulTable<ToArr<Replace<Digits, Zero>>>;
type MulTable<A, B> = AsStr<Get<Get<InnerMulTable, A>, B>>;
type TrimEndZeros<S> = S extends `${infer T}0` ? TrimEndZeros<T> : S;
/* main */
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint,
> = Reverse<InnerMultiply<Reverse<`${A}`>, Reverse<`${B}`>>>;
type InnerMultiply<
A extends string,
B extends string,
> = A extends `${infer FirstA}${infer RestA}`
? B extends `${infer FirstB}${infer RestB}`
? InnerSum<
MulTable<FirstA, FirstB>,
InnerSum<
TrimEndZeros<`${Zero}${InnerMultiply<RestA, FirstB>}`>,
InnerSum<
TrimEndZeros<`${Zero}${InnerMultiply<RestB, FirstA>}`>,
TrimEndZeros<`${Zero}${Zero}${InnerMultiply<RestB, RestA>}`>
>
>
>
: ''
: '';
Solution by ryo-mf-fjt #11817
This is a nice small solution that works for multiplication of not too big numbers e.g. 80 x 120
type Multiply<
A extends number | string | bigint,
B extends number | string | bigint,
AArr extends 0[] = [],
BArr extends 0[] = [],
Result extends 0[] = [],
>
= `${A}` extends `${AArr['length']}`
? `${B}` extends `${BArr['length']}`
? `${Result['length']}`
: Multiply<A, B, AArr, [...BArr, 0], [...Result, ...AArr]>
: Multiply<A, B, [...AArr, 0]>
And this is the full solution that passes all test cases
The idea is to represent the multiplication of a big number as a sum of not that many numbers. E. g. 123 x 45
could be represented as 15 + 120 + 100 + 800 + 500 + 4000
, or
(3 * 5) + (3 * 4 * 10) + (2 * 5 * 10) + (2 * 4 * 100) + (1 * 5 * 100) * (1 * 4 * 1000)
. Multiplication of digits can be done with tuples concatenation or with a table of predefined results while multiplication on 10 ^ n
is just adding trailing zeros to the result. The n
in that 10 ^ n
is the sum of positions of multiplied digits e.g. for 2 * 4 * 100
, 2
is the second digit in 123
and 4
is the second digit in 45
A decision has been made to represent numbers as Tuples of digits e.g. 23
is [2, 3]
. It allows to easily pick the last digit and compare it to tuple length without additional conversions
So Multiply
would convert A
and B
into Tuples and pass them to MultiplyToSum
that would transform them into a Tuple of numbers with all possible multiplications of digits of A
and B
multiplied by 10 ^ n
where n
depends on the positions of specific digits in A
and B
Then the result tuple of numbers would be summed with Sum
Then trailing zeros from the sum would be trimmed with TrimZeros
e.g. [0, 5, 5, 3, 5]
would become [5, 5, 3, 5]
And finally, the tuple of digits would be converted to string e.g. [5, 5, 3, 5]
would become 5535
// Multiplication part.
type Multiply<
A extends number | string | bigint, B extends number | string | bigint,
ATuple extends number[] = ToTuple<A>, BTuple extends number[] = ToTuple<B>,
> = ToString<TrimZeros<Sum<MultiplyToSum<ATuple, BTuple>>>>;
type MultiplyToSum<
A extends number[],
B extends number[],
Result extends number[][] = [],
FullB extends number[] = B,
ABTrailingZeros extends 0[] = [],
ATrailingZeros extends 0[] = ABTrailingZeros
> =
A extends [...infer AS extends number[], infer AL extends number]
? B extends [...infer BS extends number[], infer BL extends number]
? MultiplyToSum<A, BS, [...Result, [...MultTable[AL][BL], ...ABTrailingZeros]], FullB, [...ABTrailingZeros, 0], ATrailingZeros>
: MultiplyToSum<AS, FullB, Result, FullB, [...ATrailingZeros, 0]>
: Result;
// Convertion helpers
type ToString<T extends number[]> = T extends [infer F extends number, ...infer R extends number[]] ? `${F}${ToString<R>}` : '';
type TrimZeros<T extends number[]> = T extends [0, infer F extends number, ...infer R extends number[]] ? TrimZeros<[F, ...R]> : T
type StN = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
type ToTuple<N extends number | string | bigint> = `${N}` extends `${infer H}${infer T}` ? [StN[H & keyof StN], ...ToTuple<T>] : [];
// Sum part
type Sum<A extends number[][], TS extends number[] = [], N extends number[][] = []>
= A extends [[...infer NumP extends number[], infer NumLD extends number], ...infer RNum extends number[][]]
? Sum<RNum, [...TS, NumLD], NumP extends [] ? N : [...N, NumP]>
: N extends []
? SumDigits<TS>
: SumDigits<TS> extends [...infer SumP extends number[], infer SumD extends number]
? [...Sum<SumP extends [] ? N : [...N, SumP]>, SumD]
: never;
type SumDigits<A extends number[], R extends number[] = []> =
A extends [infer H extends number, ...infer T extends number[]]
? SumDigits<T, [...R, ...TupleOfLength[H]]>
: ToTuple<R['length']>
type TupleOfLength = [
[],
[0],
[0, 0],
[0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
]
type MultTable = [
[[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]],
[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]],
[[0], [2], [4], [6], [8], [1, 0], [1, 2], [1, 4], [1, 6], [1, 8]],
[[0], [3], [6], [9], [1, 2], [1, 5], [1, 8], [2, 1], [2, 4], [2, 7]],
[[0], [4], [8], [1, 2], [1, 6], [2, 0], [2, 4], [2, 8], [3, 2], [3, 6]],
[[0], [5], [1, 0], [1, 5], [2, 0], [2, 5], [3, 0], [3, 5], [4, 0], [4, 5]],
[[0], [6], [1, 2], [1, 8], [2, 4], [3, 0], [3, 6], [4, 2], [4, 8], [5, 4]],
[[0], [7], [1, 4], [2, 1], [2, 8], [3, 5], [4, 2], [4, 9], [5, 6], [6, 3]],
[[0], [8], [1, 6], [2, 4], [3, 2], [4, 0], [4, 8], [5, 6], [6, 4], [7, 2]],
[[0], [9], [1, 8], [2, 7], [3, 6], [4, 5], [5, 4], [6, 3], [7, 2], [8, 1]],
];
Solution by Alexsey #11580
type Multiply<A extends string | number | bigint, B extends string | number | bigint, R extends string = `0`>
= `${A}` extends '0' ? '0'
: `${B}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? Multiply<`${A}0`, L0, R> : L1 extends `${any}` ? Multiply<`${A}0`, L1, Sum<R, A>> :
L2 extends `${any}` ? Multiply<`${A}0`, L2, Sum<R, X2<A>>> : L3 extends `${any}` ? Multiply<`${A}0`, L3, Sum<R, X3<A>>> :
L4 extends `${any}` ? Multiply<`${A}0`, L4, Sum<R, X4<A>>> : L5 extends `${any}` ? Multiply<`${A}0`, L5, Sum<R, X5<A>>> :
L6 extends `${any}` ? Multiply<`${A}0`, L6, Sum<R, X6<A>>> : L7 extends `${any}` ? Multiply<`${A}0`, L7, Sum<R, X7<A>>> :
L8 extends `${any}` ? Multiply<`${A}0`, L8, Sum<R, X8<A>>> : L9 extends `${any}` ? Multiply<`${A}0`, L9, Sum<R, X9<A>>> : never
: R
type X2<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X2<L0, `0${Suffix}`> : L1 extends `${any}` ? X2<L1, `2${Suffix}`> :
L2 extends `${any}` ? X2<L2, `4${Suffix}`> : L3 extends `${any}` ? X2<L3, `6${Suffix}`> :
L4 extends `${any}` ? X2<L4, `8${Suffix}`> : L5 extends `${any}` ? Sum<X2<L5>, 1, `0${Suffix}`> :
L6 extends `${any}` ? Sum<X2<L6>, 1, `2${Suffix}`> : L7 extends `${any}` ? Sum<X2<L7>, 1, `4${Suffix}`> :
L8 extends `${any}` ? Sum<X2<L8>, 1, `6${Suffix}`> : L9 extends `${any}` ? Sum<X2<L9>, 1, `8${Suffix}`> : never
: Suffix
type X3<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X3<L0, `0${Suffix}`> : L1 extends `${any}` ? X3<L1, `3${Suffix}`> :
L2 extends `${any}` ? X3<L2, `6${Suffix}`> : L3 extends `${any}` ? X3<L3, `9${Suffix}`> :
L4 extends `${any}` ? Sum<X3<L4>, 1, `2${Suffix}`> : L5 extends `${any}` ? Sum<X3<L5>, 1, `5${Suffix}`> :
L6 extends `${any}` ? Sum<X3<L6>, 1, `8${Suffix}`> : L7 extends `${any}` ? Sum<X3<L7>, 2, `1${Suffix}`> :
L8 extends `${any}` ? Sum<X3<L8>, 2, `4${Suffix}`> : L9 extends `${any}` ? Sum<X3<L9>, 2, `7${Suffix}`> : never
: Suffix
type X4<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X4<L0, `0${Suffix}`> : L1 extends `${any}` ? X4<L1, `4${Suffix}`> :
L2 extends `${any}` ? X4<L2, `8${Suffix}`> : L3 extends `${any}` ? Sum<X4<L3>, 1, `2${Suffix}`> :
L4 extends `${any}` ? Sum<X4<L4>, 1, `6${Suffix}`> : L5 extends `${any}` ? Sum<X4<L5>, 2, `0${Suffix}`> :
L6 extends `${any}` ? Sum<X4<L6>, 2, `4${Suffix}`> : L7 extends `${any}` ? Sum<X4<L7>, 2, `8${Suffix}`> :
L8 extends `${any}` ? Sum<X4<L8>, 3, `2${Suffix}`> : L9 extends `${any}` ? Sum<X4<L9>, 3, `6${Suffix}`> : never
: Suffix
type X5<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X5<L0, `0${Suffix}`> : L1 extends `${any}` ? X5<L1, `5${Suffix}`> :
L2 extends `${any}` ? Sum<X5<L2>, 1, `0${Suffix}`> : L3 extends `${any}` ? Sum<X5<L3>, 1, `5${Suffix}`> :
L4 extends `${any}` ? Sum<X5<L4>, 2, `0${Suffix}`> : L5 extends `${any}` ? Sum<X5<L5>, 2, `5${Suffix}`> :
L6 extends `${any}` ? Sum<X5<L6>, 3, `0${Suffix}`> : L7 extends `${any}` ? Sum<X5<L7>, 3, `5${Suffix}`> :
L8 extends `${any}` ? Sum<X5<L8>, 4, `0${Suffix}`> : L9 extends `${any}` ? Sum<X5<L9>, 4, `5${Suffix}`> : never
: Suffix
type X6<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X6<L0, `0${Suffix}`> : L1 extends `${any}` ? X6<L1, `6${Suffix}`> :
L2 extends `${any}` ? Sum<X6<L2>, 1, `2${Suffix}`> : L3 extends `${any}` ? Sum<X6<L3>, 1, `8${Suffix}`> :
L4 extends `${any}` ? Sum<X6<L4>, 2, `4${Suffix}`> : L5 extends `${any}` ? Sum<X6<L5>, 3, `0${Suffix}`> :
L6 extends `${any}` ? Sum<X6<L6>, 3, `6${Suffix}`> : L7 extends `${any}` ? Sum<X6<L7>, 4, `2${Suffix}`> :
L8 extends `${any}` ? Sum<X6<L8>, 4, `8${Suffix}`> : L9 extends `${any}` ? Sum<X6<L9>, 5, `4${Suffix}`> : never
: Suffix
type X7<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X7<L0, `0${Suffix}`> : L1 extends `${any}` ? X7<L1, `7${Suffix}`> :
L2 extends `${any}` ? Sum<X7<L2>, 1, `4${Suffix}`> : L3 extends `${any}` ? Sum<X7<L3>, 2, `1${Suffix}`> :
L4 extends `${any}` ? Sum<X7<L4>, 2, `8${Suffix}`> : L5 extends `${any}` ? Sum<X7<L5>, 3, `5${Suffix}`> :
L6 extends `${any}` ? Sum<X7<L6>, 4, `2${Suffix}`> : L7 extends `${any}` ? Sum<X7<L7>, 4, `9${Suffix}`> :
L8 extends `${any}` ? Sum<X7<L8>, 5, `6${Suffix}`> : L9 extends `${any}` ? Sum<X7<L9>, 6, `3${Suffix}`> : never
: Suffix
type X8<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X8<L0, `0${Suffix}`> : L1 extends `${any}` ? X8<L1, `8${Suffix}`> :
L2 extends `${any}` ? Sum<X8<L2>, 1, `6${Suffix}`> : L3 extends `${any}` ? Sum<X8<L3>, 2, `4${Suffix}`> :
L4 extends `${any}` ? Sum<X8<L4>, 3, `2${Suffix}`> : L5 extends `${any}` ? Sum<X8<L5>, 4, `0${Suffix}`> :
L6 extends `${any}` ? Sum<X8<L6>, 4, `8${Suffix}`> : L7 extends `${any}` ? Sum<X8<L7>, 5, `6${Suffix}`> :
L8 extends `${any}` ? Sum<X8<L8>, 6, `4${Suffix}`> : L9 extends `${any}` ? Sum<X8<L9>, 7, `2${Suffix}`> : never
: Suffix
type X9<A extends string | number | bigint, Suffix extends string = ''>
= `${A}` extends `${infer L0}0` | `${infer L1}1` | `${infer L2}2` | `${infer L3}3` | `${infer L4}4` | `${infer L5}5` | `${infer L6}6` | `${infer L7}7` | `${infer L8}8` | `${infer L9}9`
? L0 extends `${any}` ? X9<L0, `0${Suffix}`> : L1 extends `${any}` ? X9<L1, `9${Suffix}`> :
L2 extends `${any}` ? Sum<X9<L2>, 1, `8${Suffix}`> : L3 extends `${any}` ? Sum<X9<L3>, 2, `7${Suffix}`> :
L4 extends `${any}` ? Sum<X9<L4>, 3, `6${Suffix}`> : L5 extends `${any}` ? Sum<X9<L5>, 4, `5${Suffix}`> :
L6 extends `${any}` ? Sum<X9<L6>, 5, `4${Suffix}`> : L7 extends `${any}` ? Sum<X9<L7>, 6, `3${Suffix}`> :
L8 extends `${any}` ? Sum<X9<L8>, 7, `2${Suffix}`> : L9 extends `${any}` ? Sum<X9<L9>, 8, `1${Suffix}`> : never
: Suffix
type Sum<A extends string | number | bigint, B extends string | number | bigint, Suffix extends string = '', P extends string = `${A}+${B}`>
= P extends
Match<'00', infer C00, infer D00> | Match<'19'|'28'|'37'|'46'|'55', infer C10, infer D10> |
Match<'01', infer C01, infer D01> | Match<'29'|'38'|'47'|'56', infer C11, infer D11> |
Match<'02'|'11', infer C02, infer D02> | Match<'39'|'48'|'57'|'66', infer C12, infer D12> |
Match<'03'|'12', infer C03, infer D03> | Match<'49'|'58'|'67', infer C13, infer D13> |
Match<'04'|'13'|'22', infer C04, infer D04> | Match<'59'|'68'|'77', infer C14, infer D14> |
Match<'05'|'14'|'23', infer C05, infer D05> | Match<'69'|'78', infer C15, infer D15> |
Match<'06'|'15'|'24'|'33', infer C06, infer D06> | Match<'79'|'88', infer C16, infer D16> |
Match<'07'|'16'|'25'|'34', infer C07, infer D07> | Match<'89', infer C17, infer D17> |
Match<'08'|'17'|'26'|'35'|'44', infer C08, infer D08> | Match<'99', infer C18, infer D18> |
Match<'09'|'18'|'27'|'36'|'45', infer C09, infer D09>
? C00 extends `${any}` ? Sum<C00, D00, `0${Suffix}`> : C10 extends `${any}` ? Sum<Sum<C10, D10>, 1, `0${Suffix}`> :
C01 extends `${any}` ? Sum<C01, D01, `1${Suffix}`> : C11 extends `${any}` ? Sum<Sum<C11, D11>, 1, `1${Suffix}`> :
C02 extends `${any}` ? Sum<C02, D02, `2${Suffix}`> : C12 extends `${any}` ? Sum<Sum<C12, D12>, 1, `2${Suffix}`> :
C03 extends `${any}` ? Sum<C03, D03, `3${Suffix}`> : C13 extends `${any}` ? Sum<Sum<C13, D13>, 1, `3${Suffix}`> :
C04 extends `${any}` ? Sum<C04, D04, `4${Suffix}`> : C14 extends `${any}` ? Sum<Sum<C14, D14>, 1, `4${Suffix}`> :
C05 extends `${any}` ? Sum<C05, D05, `5${Suffix}`> : C15 extends `${any}` ? Sum<Sum<C15, D15>, 1, `5${Suffix}`> :
C06 extends `${any}` ? Sum<C06, D06, `6${Suffix}`> : C16 extends `${any}` ? Sum<Sum<C16, D16>, 1, `6${Suffix}`> :
C07 extends `${any}` ? Sum<C07, D07, `7${Suffix}`> : C17 extends `${any}` ? Sum<Sum<C17, D17>, 1, `7${Suffix}`> :
C08 extends `${any}` ? Sum<C08, D08, `8${Suffix}`> : C18 extends `${any}` ? Sum<Sum<C18, D18>, 1, `8${Suffix}`> :
C09 extends `${any}` ? Sum<C09, D09, `9${Suffix}`> : never
: `${A}${B}${Suffix}`
type Match<P extends string, C extends string, D extends string> = P extends `${infer X}${infer Y}` ? `${C}${X}+${D}${Y}` | `${C}${Y}+${D}${X}` : never
Solution by teamchong #11426
type ArrayL<L extends string, R extends unknown[] = []> =
`${R['length']}` extends L
? R
: ArrayL<L , [...R, unknown]>
type S2Arr<S extends string, R extends string[] = []> =
S extends `${infer X}${infer Y}`
? S2Arr<Y, [...R, X]>
: R
type BitAdd<X extends string, Y extends string, Flag extends string> =
`${[...ArrayL<X>, ...ArrayL<Y>, ...ArrayL<Flag>]['length'] & number}` extends `${infer A}${infer A1}${infer A2}`
? [A, A1] : ['0', `${[...ArrayL<X>, ...ArrayL<Y>, ...ArrayL<Flag>]['length'] & number}`]
type StrArr<X extends string[], Y extends string> = [...X, Y]
type _Sum<X extends string[], Y extends string[], R extends string = '', Flag extends string = '0'> =
X extends StrArr<infer X1, infer X2>
? Y extends StrArr<infer Y1, infer Y2>
? _Sum<X1, Y1, `${BitAdd<X2, Y2, Flag>[1]}${R}`, BitAdd<X2, Y2, Flag>[0]>
: _Sum<X1, [], `${BitAdd<X2, '0', Flag>[1]}${R}`, BitAdd<X2, '0', Flag>[0]>
: Y extends StrArr<infer Y1, infer Y2>
? _Sum<[], Y1, `${BitAdd<'0', Y2, Flag>[1]}${R}`, BitAdd<'0', Y2, Flag>[0]>
: Flag extends '1'
? `1${R}`
: R
type Sum<A extends string | number | bigint, B extends string | number | bigint> = _Sum<S2Arr<`${A}`>, S2Arr<`${B}`>>
type ArraySum<Arr extends string[], R extends string = '0'> =
Arr extends StrArr<infer X, infer Y>
? ArraySum<X, Sum<R, Y>>
: R
type TimeLess10<Num extends string, T extends string, Iter extends unknown[] = [], Res extends string = '0'> =
`${Iter['length']}` extends T
? Res
: TimeLess10<Num, T, [...Iter, unknown], Sum<Num, Res>>
type _Multiply<X extends string, Y extends string[], R extends string[] = [], Flag extends string = ''> =
X extends '0'
? '0'
: Y extends StrArr<infer Y1, infer Y2>
? _Multiply<X, Y1, [...R, TimeLess10<`${X}${Flag}`, Y2>], `${0}${Flag}`>
: ArraySum<R>
type Multiply<A extends string | number | bigint, B extends string | number | bigint> = _Multiply<`${A}`, S2Arr<`${B}`>>
Solution by fangyang921017 #10339
// from type Sum
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}`>>>
// Sum end
type SimpleMutil<A extends string, B extends any[]> = B extends [infer _, ...infer R]
? Sum<A, SimpleMutil<A, R>>
: '0'
type Multi<A extends Computable, B extends Computable> = SimpleMutil<`${A}`, NumberToTuple<B>>
type Multiply<A extends Computable, B extends Computable, Res extends string = ''> =
`${B}` extends `${infer L}${infer R}`
? Multiply<A, R, Sum<`${Res}${Res extends '' ? '' : 0}`, Multi<A, L>>>
: TrimLeft<Res, '0'> extends '' ? '0' :TrimLeft<Res, '0'>
type TrimLeft<L extends string, R extends string> = L extends `${R}${infer S}` ? TrimLeft<S, R> : L
Solution by ch3cknull #8050
/**
* 4->[0,0,0,0]
*/
type numToTupl<
T extends string,
R extends any[] = []
> = `${R["length"]}` extends T ? R : numToTupl<T, [...R, 0]>;
type TenRes<base extends string, N extends string> = `${base}${N}`;
/**
* 9 + 1 = 10
* 8 + 8 = 16
*/
type SumTen<L extends string, R extends string> = [
...numToTupl<L>,
...numToTupl<R>
]["length"] extends NumberInferType<infer SumRes>
? `${SumRes}`
: never;
/**
* 个位数 * 个位数
* 2 * 9
*/
type MulTen<
L extends string,
R extends string,
Res extends string = "0"
> = numToTupl<L> extends [infer _, ...infer LN]
? MulTen<`${LN["length"]}`, R, SumTen<Res, R>>
: Res;
/**
* n位数 * 个位数
* 123 * 4
* 3 * 2
* 121021 * 5
*/
type Mul_N_AND_ONE<
L extends string,
R extends string,
Res extends string = "0"
> = L extends `${infer A}${infer B}`
? Mul_N_AND_ONE<B, R, Sum<`${Res}0`, MulTen<A, R>>>
: Res;
type NumberInferType<T extends number> = T;
type StringArrInferType<T extends string[], S extends string> = [...T, S];
type StringInferType<L extends string, R extends string> = `${L}${R}`;
/**
* "1234"->["1","2","3","4"]
*/
type ToStringArr<T extends string | number | bigint> =
`${T}` extends StringInferType<infer L, infer R>
? [L, ...ToStringArr<R>]
: [];
/**
* ["1","2","3","4"]->"1234"
* ["0","2"]->"02"
*/
type StringArrToString<T extends string[]> = T extends StringArrInferType<
infer L,
infer R
>
? `${StringArrToString<L>}${R}`
: "";
/**
* 012 -> 12
* 0 -> 0
* 101 -> 101
*/
type RemoveZero<T> = T extends `0${infer R}`
? RemoveZero<R>
: T extends ""
? "0"
: T;
/**
* ['1','2'] ['1'] long -> ['1','2']
* ['1','2'] ['1'] short -> ['1']
*/
type findArr<
T extends string[],
R extends string[],
type extends "long" | "short"
> = numToTupl<`${T["length"]}`> extends [
...numToTupl<`${R["length"]}`>,
...infer _
]
? type extends "long"
? T
: R
: type extends "long"
? R
: T;
type _Sum<
L extends string[],
R extends string[],
base extends string = "0",
Res extends string[] = []
> = L extends StringArrInferType<infer LL, infer LC>
? R extends StringArrInferType<infer RR, infer RC>
? SumTen<SumTen<LC, RC>, base> extends TenRes<infer A, infer B>
? B extends ""
? _Sum<LL, RR, "0", [A, ...Res]>
: _Sum<LL, RR, A, [B, ...Res]>
: never
: SumTen<SumTen<LC, "0">, base> extends TenRes<infer A, infer B>
? B extends ""
? _Sum<LL, [], "0", [A, ...Res]>
: _Sum<LL, [], A, [B, ...Res]>
: never
: base extends "1"
? ["1", ...Res]
: Res;
type Sum<
A extends string | number | bigint,
B extends string | number | bigint
> = RemoveZero<
StringArrToString<
_Sum<
findArr<ToStringArr<A>, ToStringArr<B>, "long">,
findArr<ToStringArr<A>, ToStringArr<B>, "short">
>
>
>;
type _Multiply<
L extends string,
R extends string,
Res extends string = "0"
> = R extends `${infer A}${infer B}`
? _Multiply<L, B, Sum<`${Res}0`, Mul_N_AND_ONE<L, A>>>
: Res;
type Multiply<
L extends string | number | bigint,
R extends string | number | bigint
> = _Multiply<`${L}`, `${R}`>;
Solution by baian1 #6059
// your answers
type Reverse<A> =
`${A}` extends `${infer AH}${infer AT}`
? `${Reverse<AT>}${AH}` : A
type Digs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
type DigsNext<I = Digs, R = {}> =
I extends [infer Head, infer Next, ...infer Tail]
? DigsNext<[Next, ...Tail], R & Record<Head, Next>>
: {[K in keyof R]: R[K]}
type DigsPrev = {[K in keyof DigsNext as DigsNext[K]]: K}
type AddOne<A> =
A extends `${infer AH}${infer AT}`
? AH extends '9' ? `0${AddOne<AT>}` : `${DigsNext[AH]}${AT}`
: `1`
type SubOne<A> =
A extends `${infer AH}${infer AT}`
? AH extends '0' ? `9${SubOne<AT>}` : `${DigsPrev[AH]}${AT}`
: never
type Add<A, B> =
A extends `${infer AH}${infer AT}` ?
B extends `${infer BH}${infer BT}`
? BH extends '0' ? `${AH}${Add<AT, BT>}` : Add<AddOne<A>, SubOne<B>>
: A : B
type Mul<A, B, R = '0'> =
A extends '0' ? R :
B extends '0' ? R :
A extends `${infer AH}${infer AT}`
? AH extends '0' ? Mul<AT, `0${B}`, R> : Mul<SubOne<A>, B, Add<R, B>>
: R
type Multiply<A extends string | number | bigint, B extends string | number | bigint> =
Reverse<Mul<Reverse<A>, Reverse<B>>>
Solution by Sobes76rus #5814
// Makes a tuple of a given size
type Tuple<S extends string, U = never, A extends U[] = []> =
`${A['length']}` extends S ? A : Tuple<S, U, [...A, U]>
// Flattens a 2D array into a plain array (e.g. [[], [1, 1], [1]] => [1,1,1])
type Flatten<T extends U[][], U = never, A extends U[] = []> =
T extends [infer F, ...infer R] ? Flatten<R, U, [...A, ...F]> : A
// Gets rid of starting C characters in S string (e.g. '00012' => '12')
type TrimLeft<S extends string, C extends string> =
S extends `${C}${infer R}` ? TrimLeft<R, C> : S
// Converts a string to a reverse array of digits (e.g. 103 => ['3', '0', '1'])
type ToDigits<T extends string, A extends string[] = []> =
`${T}` extends `${infer F}${infer R}` ? ToDigits<R, [F, ...A]> : A
// Converts an inverted array of digits to a stringified number
type ToString<T extends string[], S extends string = ''> =
T extends [...infer R, infer L] ? ToString<R, `${S}${L}`> :
S extends '' ? '0' : S
// Summarizes 2 numbers, returns an inverted array of digits
type SumNumbers<A extends string, B extends string> =
ToDigits<`${[...Tuple<A>, ...Tuple<B>]['length']}`>
// Multiplies 2 numbers, returns an inverted array of digits
type MultiplyNumbers<A extends string, B extends string> =
ToDigits<`${[...Flatten<Tuple<A, Tuple<B>>>]['length']}`>
type SumDigits<A extends string[], B extends string[]> =
A extends [infer Fa, ...infer Ra] ?
B extends [infer Fb, ...infer Rb] ?
// Take both digits on the same position, sum them
SumNumbers<Fa, Fb> extends [infer Fs, ...infer Rs] ?
// Output the first digit, carry the rest to the next iteration
[Fs, ...SumDigits<Rs, SumDigits<Ra, Rb>>] : []
: A
: B extends [any, ...any[]] ?
B : []
type MultiplyNumberByDigits<A extends string, B extends string[]> =
B extends [infer Fb, ...infer Rb] ?
MultiplyNumbers<A, Fb> extends [infer Fs, ...infer Rs] ?
[Fs, ...SumDigits<Rs, MultiplyNumberByDigits<A, Rb>>] : []
: []
type MultiplyDigits<A extends string[], B extends string[]> =
A extends [infer Fa, ...infer Ra] ?
MultiplyNumberByDigits<Fa, B> extends [infer Fs, ...infer Rs] ?
[Fs, ...SumDigits<Rs, MultiplyDigits<Ra, B>] :
[]
: []
type Multiply<A extends string | number | bigint, B extends string | number | bigint> =
ToString<MultiplyDigits<
ToDigits<TrimLeft<`${A}`, '0'>>,
ToDigits<TrimLeft<`${B}`, '0'>>
>>
Solution by ssipak #4658
type N1 = [any];
type N2 = [any, any];
type N3 = [any, any, any];
type N4 = [any, any, any, any];
type N5 = [any, any, any, any, any];
type N6 = [any, any, any, any, any, any];
type N7 = [any, any, any, any, any, any, any];
type N8 = [any, any, any, any, any, any, any, any];
type N9 = [any, any, any, any, any, any, any, any, any];
type NumToTuple<N, L = N extends string | number ? `${N}` : ''> =
L extends `${N1['length']}`
? N1 : L extends `${N2['length']}`
? N2 : L extends `${N3['length']}`
? N3 : L extends `${N4['length']}`
? N4 : L extends `${N5['length']}`
? N5 : L extends `${N6['length']}`
? N6 : L extends `${N7['length']}`
? N7 : L extends `${N8['length']}`
? N8 : L extends `${N9['length']}`
? N9 : [];
type ToTuple<T extends bigint | string | number, S = `${T}`> = S extends `${infer F}${infer O}` ? [F, ...ToTuple<O>] : [];
type TuplePop<T extends any[]> = T extends [...any, infer O] ? O : '';
type TupleTail<T extends any[]> = T extends [...infer F, any] ? F : T;
type TensDigitSum<A, B, C = 0, R = [...NumToTuple<A>, ...NumToTuple<B>, ...NumToTuple<C>]['length']> = R extends number ? R : 0;
type SumToCarry<A, B, C, R extends string[] = ToTuple<TensDigitSum<A, B, C>>> = R extends [infer F, infer O] ? [F, O] : ['', R[0]];
type TupleToString<T extends any[]> = T extends [string, ...infer O] ? `${T[0]}${TupleToString<O>}` : '';
type Num = string | number | bigint;
type TupleSumTuple<A extends any[], B extends any[], R extends any[] = [], C extends any = ''> = A extends []
? (C extends '' ? [...B, ...R] : TupleSumTuple<B, [C], R>) : B extends []
? (C extends '' ? [...A, ...R] : TupleSumTuple<A, [C], R>) : SumToCarry<TuplePop<A>, TuplePop<B>, C> extends [infer C1, infer T]
? TupleSumTuple<TupleTail<A>, TupleTail<B>, [T, ...R], C1> : R;
type Cumulative<A extends any[], N extends Num, L extends any[] = [any], R extends any[] = A> = `${N}` extends `${L['length']}` ? R : Cumulative<A, N, [...L, any], TupleSumTuple<R, A>>;
type MultiplyByTuple<A extends any[], B extends any[], C extends any[] = [], R extends any[] = []> = B extends [] ? R : MultiplyByTuple<A, TupleTail<B>, [...C, '0'], TupleSumTuple<R, [...Cumulative<A, TuplePop<B>>, ...C]>>
type Multiply<A extends string | number | bigint, B extends string | number | bigint> = `${A}` extends '0'
? '0' : `${B}` extends '0'
? '0' : TupleToString<MultiplyByTuple<ToTuple<A>, ToTuple<B>>>;
Solution by venusliang #4535
ts
type arrElem = any
type arr = arrElem[];
type OpType = string | number | bigint
type Cast<T, U> = T extends U ? T : U;
type DeleteFirstElement<T extends arr> = T extends [arrElem, ...infer R] ? R : never
type ToArr<T extends string, R extends arr = []> = `${R['length']}` extends T
? R
: ToArr<T, [...R, arrElem]>
type ToArrNumber<T extends OpType, R extends arr = []> =
`${T}` extends `${infer FirstNumber}${infer RestNumbers}`
? ToArrNumber<RestNumbers, [ToArr<FirstNumber>, ...R]>
: R
type ToNumber<T extends arr, S extends string = ''> = T extends [infer FirstNumber, ...infer RestNumbers]
? ToNumber<RestNumbers, `${ FirstNumber extends arr ? FirstNumber['length'] : never }${S}`>
: S
type CombineArrNumber<
A1 extends arr, A2 extends arr, R extends arr = []
> = A1['length'] extends 0
? [...R, ...A2]
: A2['length'] extends 0
? [...R, ...A1]
: CombineArrNumber<
DeleteFirstElement<A1>,
DeleteFirstElement<A2>,
[...R, [...A1[0], ...A2[0]] ]
>
type GetRest<T extends arr, R extends arr = [[], []]> =
(R[1])['length'] extends 10
? [[arrElem], T]
: T['length'] extends 0
? [[], R[1]]
: GetRest< DeleteFirstElement<T>, [[], [arrElem, ...(R[1]) ]] >
type NormalizeArrNumber<T extends arr, R extends arr = []> = T['length'] extends 0
? R
: T['length'] extends 1
? [...R, GetRest<T[0]>[1], ...(GetRest<T[0]>[0]['length'] extends 1 ? [[arrElem]] : [])]
: NormalizeArrNumber<
[[ ...(T[1]), ...GetRest<T[0]>[0] ], ...DeleteFirstElement<DeleteFirstElement<T>>],
[...R, GetRest<T[0]>[1]]
>
type Sum<S1 extends OpType, S2 extends OpType> =
ToNumber<
Cast<NormalizeArrNumber<
Cast<CombineArrNumber<
ToArrNumber<S1>,
ToArrNumber<S2>
>, arr>
>, arr>
>
type MultiplyByNumber<M1 extends OpType, M2 extends string, R extends string = `0`, I extends arr = []> = `${I['length']}` extends M2
? R
: MultiplyByNumber<M1, M2, Sum<R, M1>, [arrElem, ...I]>
type SplitAndReverse<T extends string, R extends string[] = []> = T extends `${infer First}${infer Rest}`
? SplitAndReverse<Rest, [First, ...R]>
: R
type AddZeros<T extends arr, R extends string = ''> = T['length'] extends 0 ? R : AddZeros<DeleteFirstElement<T>, `${R}0`>
type Multiply<M1 extends OpType, Q extends OpType, M2 extends string[] = SplitAndReverse<`${Q}`>, R extends string = '', I extends arr = []> =
`${M1}` extends '0'
? '0'
: M2['length'] extends 0
? R
: Multiply<M1, Q, Cast<DeleteFirstElement<M2>, string[]>, Sum< `${MultiplyByNumber<M1, M2[0]>}${AddZeros<I>}` , R>, [arrElem, ...I]>
Solution by AlexeyDuybo #4309
type Type<Value> = Compute<Value> extends infer ComputedValue
? /* ... */ // ComputedValue gets reused deep down the conditional chain
: never
// #region Sum challenge solution
// See: https://github.com/type-challenges/type-challenges/issues/3749
type NumberLike = string | number | bigint
type NumericString = `${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`
// #region Rightmost string extraction helpers
type SplitRightMost<Type> = Type extends NumberLike
? `${Type}` extends `${infer Rest}${NumericString}`
? `${Type}` extends `${Rest}${infer Right}`
? [Rest, Right]
: never
: ['', '']
: never
type SplitRest = 0
type SplitRight = 1
type SplitGet<
Splitted,
Key extends SplitRest | SplitRight
> = Splitted[Key & keyof Splitted]
type SplitGetRest<Splitted> = SplitGet<Splitted, SplitRest>
type SplitGetRight<Splitted> = SplitGet<Splitted, SplitRight>
// #endregion
// #region Digit to tuple helpers
type DigitToTupleMap<V = unknown> = {
'': [],
'0': [],
'1': [V],
'2': [V, V],
'3': [V, V, V],
'4': [V, V, V, V],
'5': [V, V, V, V, V],
'6': [V, V, V, V, V, V],
'7': [V, V, V, V, V, V, V],
'8': [V, V, V, V, V, V, V, V],
'9': [V, V, V, V, V, V, V, V, V],
}
type CreateTuple<Length> = DigitToTupleMap[Length & keyof DigitToTupleMap]
// #endregion
type IsFalsy<Type> = Type extends '' | 0 | false | null | undefined
? true
: false
type SumDigits<First, Second, Third = '0'> = [
...CreateTuple<First>,
...CreateTuple<Second>,
...CreateTuple<Third>
]['length']
type Sum<
First,
Second,
CarryOver = '0',
SplitFirst = SplitRightMost<First>,
FirstRight = SplitGetRight<SplitFirst>,
FirstRest = SplitGetRest<SplitFirst>,
SplitSecond = SplitRightMost<Second>,
SecondRight = SplitGetRight<SplitSecond>,
SecondRest = SplitGetRest<SplitSecond>,
> = SplitRightMost<
SumDigits<FirstRight, SecondRight, CarryOver>
> extends [infer CurrentCarryOver, infer Current]
? IsFalsy<FirstRest> extends true
? IsFalsy<SecondRest> extends true
// FirstRest = 0, SecondRest = 0
? `${CurrentCarryOver & string}${Current & string}`
// FirstRest = 0, SecondRest = x
: `${Sum<SecondRest, CurrentCarryOver>}${Current & string}`
: IsFalsy<SecondRest> extends true
// FirstRest = x, SecondRest = 0
? `${Sum<FirstRest, CurrentCarryOver>}${Current & string}`
// FirstRest = x, SecondRest = x
: `${Sum<FirstRest, SecondRest, CurrentCarryOver>}${Current & string}`
: never
// #endregion
// #region Multiplication challenge extension
type MultiplicationTable = [
['0', '0', '0', '0', '0', '0', '0', '0', '0', '0'],
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
['0', '2', '4', '6', '8', '10', '12', '14', '16', '18'],
['0', '3', '6', '9', '12', '15', '18', '21', '24', '27'],
['0', '4', '8', '12', '16', '20', '24', '28', '32', '36'],
['0', '5', '10', '15', '20', '25', '30', '35', '40', '45'],
['0', '6', '12', '18', '24', '30', '36', '42', '48', '54'],
['0', '7', '14', '21', '28', '35', '42', '49', '56', '63'],
['0', '8', '16', '24', '32', '40', '48', '56', '64', '72'],
['0', '9', '18', '27', '36', '45', '54', '63', '72', '81'],
]
type MultiplyDigits<
First,
Second,
> = MultiplicationTable[
CreateTuple<`${First & NumberLike}`>['length']
][
CreateTuple<`${Second & NumberLike}`>['length']
]
type Multiply<
First,
Second,
CarryOver = '0',
SplitFirst = SplitRightMost<First>,
FirstRight = SplitGetRight<SplitFirst>,
FirstRest = SplitGetRest<SplitFirst>,
SplitSecond = SplitRightMost<Second>,
SecondRight = SplitGetRight<SplitSecond>,
SecondRest = SplitGetRest<SplitSecond>,
> = '0' extends First | Second
? CarryOver
: SplitRightMost<
MultiplyDigits<FirstRight, SecondRight>
> extends [infer CurrentCarryOver, infer Current]
? IsFalsy<FirstRest> extends true
? IsFalsy<SecondRest> extends true
// FirstRest = 0, SecondRest = 0
? Sum<
`${CurrentCarryOver & string}${Current & string}`,
CarryOver
>
// FirstRest = 0, SecondRest = x
: Sum<
Current,
`${Multiply<FirstRight, SecondRest, CurrentCarryOver & string>}0`,
CarryOver
>
: IsFalsy<SecondRest> extends true
// FirstRest = x, SecondRest = 0
? Sum<
Current,
`${Multiply<FirstRest, SecondRight, CurrentCarryOver & string>}0`,
CarryOver
>
// FirstRest = x, SecondRest = x
: Sum<
Sum<
Current,
`${Multiply<FirstRight, SecondRest, CurrentCarryOver & string>}0`
>,
`${Multiply<FirstRest, Second>}0`,
CarryOver
>
: never
// #endregion
Solution by ianbunag #3758
Based on https://github.com/type-challenges/type-challenges/issues/515.
type NumberLike = string | number | bigint;
/**
* ToString<3> = '3'.
*/
type ToString<N extends NumberLike> = `${N}`;
/**
* Split<'foo'> = ['f', 'o', 'o'].
*/
type Split<S extends string> = S extends `${infer Letter}${infer Rest}`
? [Letter, ...Split<Rest>]
: [];
/**
* SumMod10[2][3] = 5.
* SumMod10[7][4] = 1.
*/
type SumMod10 = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
[2, 3, 4, 5, 6, 7, 8, 9, 0, 1],
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2],
[4, 5, 6, 7, 8, 9, 0, 1, 2, 3],
[5, 6, 7, 8, 9, 0, 1, 2, 3, 4],
[6, 7, 8, 9, 0, 1, 2, 3, 4, 5],
[7, 8, 9, 0, 1, 2, 3, 4, 5, 6],
[8, 9, 0, 1, 2, 3, 4, 5, 6, 7],
[9, 0, 1, 2, 3, 4, 5, 6, 7, 8],
];
/**
* TenOfSumOfTwoDigits[2][3] = 0.
* TenOfSumOfTwoDigits[4][8] = 1.
*/
type TenOfSumOfTwoDigits = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
type Digit = ToString<SumMod10[0][number]>;
type Tuple = readonly Digit[];
/**
* Last<['2', '3']> = '3'.
*/
type Last<T extends Tuple> = T extends []
? 0
: T extends [...infer Head, infer Element]
? Element extends Digit
? Element
: '0'
: '0';
/**
* Pop<['2', '3', '4']> = ['2', '3'].
*/
type Pop<T extends Tuple> = T extends [] ? [] : T extends [...infer Head, unknown] ? Head : [];
/**
* Join<['1', '2']> = '12'.
*/
type Join<T extends Tuple> = T extends [] ? '' : `${Join<Pop<T>>}${Last<T>}`;
/**
* TenOfSum<T, A, B> = (T + A + B) > 9 ? 1 : 0.
*/
type TenOfSum<
Ten extends 0 | 1,
A extends Digit,
B extends Digit
> = TenOfSumOfTwoDigits[A][B] extends 1 ? 1 : [SumMod10[A][B], Ten] extends [9, 1] ? 1 : 0;
/**
* TuplesAreEmpty<[], []> = true.
* TuplesAreEmpty<[], ['1']> = false.
*/
type TuplesAreEmpty<A extends Tuple, B extends Tuple> = A extends []
? B extends []
? true
: false
: false;
/**
* SumOfTuple<['2', '3'], ['9']> = ['3', '2'].
*/
type SumOfTuple<
A extends Tuple,
B extends Tuple,
Ten extends 0 | 1 = 0,
Result extends Tuple = []
> = TuplesAreEmpty<A, B> extends true
? Ten extends 1
? ['1', ...Result]
: Result
: SumOfTuple<
Pop<A>,
Pop<B>,
TenOfSum<Ten, Last<A>, Last<B>>,
[ToString<SumMod10[Ten][SumMod10[Last<A>][Last<B>]]>, ...Result]
>;
type MultiplyBy2<A> = A extends Tuple ? SumOfTuple<A, A> : [];
type MultiplyBy3<A> = A extends Tuple ? SumOfTuple<A, MultiplyBy2<A>> : [];
type MultiplyBy4<A> = A extends Tuple ? MultiplyBy2<MultiplyBy2<A>> : [];
type MultiplyBy5<A> = A extends Tuple ? SumOfTuple<A, MultiplyBy4<A>> : [];
type MultiplyBy6<A> = A extends Tuple ? MultiplyBy2<MultiplyBy3<A>> : [];
type MultiplyBy7<A> = A extends Tuple ? SumOfTuple<A, MultiplyBy6<A>> : [];
type MultiplyBy8<A> = A extends Tuple ? MultiplyBy2<MultiplyBy4<A>> : [];
type MultiplyBy9<A> = A extends Tuple ? MultiplyBy3<MultiplyBy3<A>> : [];
type MultiplyBy10<A> = A extends Tuple ? MultiplyBy2<MultiplyBy5<A>> : [];
type SumOf10AandB<A extends Tuple, B extends Tuple> = SumOfTuple<MultiplyBy10<A>, B>;
type MultiplyOfTuple<
A extends Tuple,
B extends Tuple,
LastA extends Digit = Last<A>,
PopA extends Tuple = Pop<A>
> = A extends []
? ['0']
: LastA extends '0'
? MultiplyBy10<MultiplyOfTuple<PopA, B>>
: LastA extends '1'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, B>
: LastA extends '2'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy2<B>>
: LastA extends '3'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy3<B>>
: LastA extends '4'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy4<B>>
: LastA extends '5'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy5<B>>
: LastA extends '6'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy6<B>>
: LastA extends '7'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy7<B>>
: LastA extends '8'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy8<B>>
: LastA extends '9'
? SumOf10AandB<MultiplyOfTuple<PopA, B>, MultiplyBy9<B>>
: [];
/**
* Multiply<2, 3> = '6'.
*/
type Multiply<A extends NumberLike, B extends NumberLike> = Join<
MultiplyOfTuple<Split<ToString<A>>, Split<ToString<B>>>
>;
Solution by uid11 #840
// It is all about length of tuples
// Declare unique length filler to mimic numbers by length of arrays
type DeclareUniqueSymbol = { readonly 0: unique symbol }
type LF = DeclareUniqueSymbol[0];
// Programmatically mapping numbers from 0 to 9 to arrays of matching length
type CreateNumbersLikeMap0_9<
Arr extends any[] = []
> = `${Arr['length']}` extends `${any}${infer R}`
? R extends ''
? [Arr, ...CreateNumbersLikeMap0_9<[...Arr, LF]>]
: []
: never;
// Create the map
type NumbersLikeMap0_9 = CreateNumbersLikeMap0_9;
// Type of single digits in string
type DigitString = keyof NumbersLikeMap0_9 & `${number}`;
type Key0_1 = '0' | '1';
type DigitLike = LF[];
// NumberLike keep DigitsLike in reverse order
type NumberLike = DigitLike[];
type CarryingDigitLike = [] | [LF];
type PairOfNumbersLike = [NumberLike, NumberLike];
type PairsOfDigitsAndCaryingDigitsLikeArray = [DigitLike, CarryingDigitLike][];
type DigitLikeGuard<X extends DigitLike> = X;
type NumberLikeGuard<X extends NumberLike> = X;
type PairOfNumbersLikeGuard<X extends PairOfNumbersLike> = X;
type PairsOfDigitsAndCaryingDigitsLikeArrayGuard<
X extends PairsOfDigitsAndCaryingDigitsLikeArray
> = X;
// Implementation of sum of single digits converted into pair of DigitsLike and CaryingDigitsLike
type SumSingleDigits<
A extends DigitLike,
B extends DigitLike,
CD extends CarryingDigitLike
> = [...A, ...B, ...CD] extends infer Result
? Result extends [...NumbersLikeMap0_9[9], any, ...infer Over]
? [Over, [LF]]
: [Result, []]
: never;
// Having array of pairs of DigitsLike and CaryingDigitsLike we want to
// extract only given place members into separate array one of the following:
// DigitsLike array and CaryingDigitsLike array that are essentially NumbersLike
type ExtractArray<
Pairs extends PairsOfDigitsAndCaryingDigitsLikeArray,
Key extends Key0_1
> = {
[I in keyof Pairs]: Pairs[I] extends [DigitLike, CarryingDigitLike]
? Pairs[I][Key]
: never;
};
// Shift array of CarryingDigitsLike for the next sum iteration
type ShiftArray<Arr extends CarryingDigitLike[]> = Arr extends [...infer E, []]
? [[], ...E]
: [[], ...Arr];
// Separate pairs of DigitsLike and CaryingDigitsLike into two NumbersLike
// preparing for next iteration
type SeparateArrays<
Arr extends [DigitLike, CarryingDigitLike][],
U = [any, any]
> = {
[I in keyof U]: I extends '0'
? ExtractArray<Arr, I>
: I extends '1'
// Note to shift CarryingDigitsLike in array to comply of being next iteration summand
? ShiftArray<ExtractArray<Arr, I>>
: never;
};
// Iteratively perform sum until NumbersLike of carying digits is empty.
// Make sure to place shorter summand first
type SumImpl<Pair extends PairOfNumbersLike, A = Pair[0], B = Pair[1]> = {
[I in keyof B]: I extends keyof A
? [A[I], B[I]] extends [DigitLikeGuard<infer AI>, DigitLikeGuard<infer BI>]
? SumSingleDigits<AI, BI, []>
: never
: [B[I], []];
} extends PairsOfDigitsAndCaryingDigitsLikeArrayGuard<infer Iteration>
? SeparateArrays<Iteration> extends PairOfNumbersLikeGuard<infer NextPair>
// Examine if carrying digits number consists of zeroes to finish calculations
? NextPair[1] extends [][]
? NextPair[0]
: SumImpl<NextPair>
: never
: never;
// Prepare string for multiplication
// (divide string apart reverting and convert into NumbersLike)
type SplitStringReverting<
NL extends string | number | bigint,
S extends string = `${NL}`
> = S extends `${infer First}${infer Rest}`
? [...SplitStringReverting<Rest>, NumbersLikeMap0_9[First & DigitString]]
: [];
// Combine NumbersLike into string
type CombineArrayToString<Arr extends NumberLike> = Arr extends [
DigitLikeGuard<infer First>,
...NumberLikeGuard<infer Rest>
]
? `${CombineArrayToString<Rest>}${First['length']}`
: '';
// Sort out multiplying members placing the longer one first
type ArrangeArraysByLength<
Pair extends PairOfNumbersLike,
A = Pair[0],
B = Pair[1]
> = keyof A extends keyof A & keyof B ? [B, A] : Pair;
// Multiply NumberLike and DigitLike iteratively
type MultiplyByOneDigit<A extends NumberLike, M extends DigitLike> = M extends []
? [[]]
: M extends [any, ...DigitLikeGuard<infer MRest>]
? MRest extends []
? A
: SumImpl<[A, MultiplyByOneDigit<A, MRest>]>
: never;
// Iteratively perform multiplication extracting DigitsLike from second member one by one
type MultiplyImpl<
Pair extends PairOfNumbersLike,
A extends NumberLike = Pair[0],
B = Pair[1]
> = B extends [DigitLikeGuard<infer BNext>, ...NumberLikeGuard<infer BRest>]
? MultiplyByOneDigit<A, BNext> extends NumberLikeGuard<infer Iteration>
? BRest extends []
? Iteration
// Add tailing zero to result of next iteration and add it to intermediate result
: SumImpl<[Iteration, [[], ...MultiplyImpl<[A, BRest]>]]>
: never
: never;
type Multiply<
A extends string | number | bigint,
B extends string | number | bigint
> = CombineArrayToString<
MultiplyImpl<
// Sort multiplication members to achieve deeper possible recursion
ArrangeArraysByLength<[SplitStringReverting<A>, SplitStringReverting<B>]>
>
>;
Solution by turtleflyer #809
type Digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
type Digit = Digits[number];
type Tuple = readonly Digit[] | unknown[];
type Head<T extends Tuple> = T extends [infer F, ...infer _] ? F : '0';
type Tail<T extends Tuple> = T extends [infer _, ...infer R] ? R : [];
type RotateL<T extends Tuple> = T extends [infer F, ...infer R] ? [...R, F]: [];
type RotateR<T extends Tuple> = T extends [] ? [] : T extends [...infer I, infer L] ? [L, ...I] : never;
type prev = RotateR<Digits> & Record<string, never>
type SumMod10 = {
[d in Digit]: d extends '0' ? Digits : RotateL<SumMod10[prev[d]]>;
};
type mapZero<T extends [...Digit[]]> = {
[I in keyof T]: '0';
};
type Carry10 = {
[d in Digit]: d extends '0' ? mapZero<Digits> : [...Tail<Carry10[prev[d]]>, '1']
};
type addDigits<A extends Digit, B extends Digit> = {
current: SumMod10[A][B],
carry: Carry10[A][B],
};
type DigitAdded = { current: Digit; carry: Digit };
type DigitAddedInfer<Cur extends Digit, Car extends Digit> = { current: Cur; carry: Car };
type mapAddDigits<T extends [...Digit[]], D extends Digit> = {
[I in keyof T]: T[I] extends Digit ? addDigits<T[I], D> : never
};
type SumDigits = {
[d in Digit]: mapAddDigits<Digits, d>
};
type addAddedInMultiplyDigits<
A extends DigitAdded,
D extends Digit,
Current extends Digit = SumMod10[A['current']][D],
Carry extends Digit = SumMod10[Carry10[A['current']][D]][A['carry']] // assume not carry to hundred
> = DigitAddedInfer<Current, Carry>;
type addDigitsToDigitAdded<T extends any> = { // TODO restrict T
[I in Digit]:
I extends keyof T ?
T[I] extends infer DA ?
DA extends DigitAdded ?
addAddedInMultiplyDigits<DA, Digits[I]>
: never : never : never
};
type MultiplyDigits = {
[d in Digit]:
d extends '0' ? mapAddDigits<mapZero<Digits>, '0'> : addDigitsToDigitAdded<MultiplyDigits[prev[d]]>
};
type multiplyTupleDigit<T extends Tuple, D extends Digit, Carry extends Digit = '0'> =
T extends [] ?
Carry extends '0' ? [] : [Carry]
: addAddedInMultiplyDigits<MultiplyDigits[Head<T>][D], Carry> extends DigitAddedInfer<infer Cur, infer Car> ?
[Cur, ...multiplyTupleDigit<Tail<T>, D, Car>]
: never
;
type addTupleDigit<T extends Tuple, D extends Digit, Carry extends Digit = '0'> =
T extends [] ?
addDigits<D, Carry> extends DigitAddedInfer<infer Cur, infer Car> ?
Car extends '0' ? Cur extends '0' ? [] : [Cur] : [Cur, Car]
: never
: addAddedInMultiplyDigits<addDigits<Head<T>, D>, Carry> extends DigitAddedInfer<infer Cur, infer Car> ?
[Cur, ...addTupleDigit<Tail<T>, '0', Car>] : never
;
type addTuples<T1 extends Tuple, T2 extends Tuple, Carry extends Digit = '0'> =
T1 extends [] ? addTupleDigit<T2, Carry> :
T2 extends [] ? addTupleDigit<T1, Carry> :
addAddedInMultiplyDigits<addDigits<Head<T1>, Head<T2>>, Carry> extends DigitAddedInfer<infer Cur, infer Car> ?
[Cur, ...addTuples<Tail<T1>, Tail<T2>, Car>] : never
;
type MultiplyTuples<Multiplyee extends Tuple, Multiplyer extends Tuple, Carry extends Tuple = ['0']> =
Multiplyer extends [] ? Carry :
addTuples<multiplyTupleDigit<Multiplyee, Head<Multiplyer>>, Carry> extends infer Multiplyed ?
Multiplyed extends [infer F]
? [F, ...MultiplyTuples<Multiplyee, Tail<Multiplyer>, ['0']>]
: Multiplyed extends Tuple ? [Head<Multiplyed>, ...MultiplyTuples<Multiplyee, Tail<Multiplyer>, Tail<Multiplyed>>]
: never : never
;
type NumberLike = string | number | bigint;
type NumberLikeToString<N extends NumberLike> = `${N}`;
type SplitRevert<S extends string> = S extends `${infer Letter}${infer Rest}`
? [...SplitRevert<Rest>, Letter]
: [];
type ToTuple<N extends NumberLike> = SplitRevert<NumberLikeToString<N>>;
type JoinRevert<T extends Tuple> = T extends [] ? '' : `${JoinRevert<Tail<T>>}${Head<T>}`;
type RemoveHeadingZeros<T extends string> = T extends `0${infer R}` ? RemoveHeadingZeros<R> : T;
type TupleToString<T extends Tuple> = RemoveHeadingZeros<JoinRevert<T>> extends infer S ? S extends '' ? '0' : S : never;
type Multiply<A extends NumberLike, B extends NumberLike> =
TupleToString<MultiplyTuples<ToTuple<A>, ToTuple<B>>>
;
Solution by etoriet #704