写在前面
本文执行环境typescript,版本4.6.2
复制代码
背景
之前推算过一次斐波那契函数 -> 文章:用typescript类型推算斐波那契
本以为万事大吉了,结果原来是因为我的测试例子不够,竟然才推算到12位电脑就罢工!
因为上文实现的 +1操作
就是 push数组后获取length 来实现,所有的加法都通过递归 +1操作
来实现,搁我也罢工了,那怎么解决?
重构吧!
重构
思考吧,怎么重构?
斐波那契本身就需要递归,这个跳不过,看来优化重点就是加法。敲黑板,重点是:
重构加法
复制代码
而加法就要先优化 +1操作
,因为加法机制是对位相加,如果有进位则进位
重构+1操作
其实很简单,实现个位数的 +1 操作,这是加法的基础
type G_ADD_ONE<N extends string> = N extends '0' ? '1' :
N extends '1' ? '2' :
N extends '2' ? '3' :
N extends '3' ? '4' :
N extends '4' ? '5' :
N extends '5' ? '6' :
N extends '6' ? '7' :
N extends '7' ? '8' :
N extends '8' ? '9' :
N extends '9' ? '10' :
'';
复制代码
加法的规则是从个位数开始相加,有进位则进位,所以需要递归获取到单个数字
// 获取末尾的数字
type GetEnd<N extends string> = N extends simpleNum ? N :
N extends `${string}${infer P}` ? GetEnd<P> : '';
// 获取末尾之外的数字
type GetEndPre<N extends string> = N extends simpleNum ? '' :
N extends `${infer P}${GetEnd<N>}` ? P : '';
type end1 = GetEnd<'123'>; // 3
type end2 = GetEndPre<'123'>; // 12
复制代码
+1操作的逻辑是:
获取到数字个位后就可以进行任意数的+1操作
复制代码
之前n个数需要递归n次,即5+6需要递归11次 +1操作
,现在完成任意数的 +1 只需要递归数字长度即可
// 个位数
type simpleNum = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
type ADD_ONE<N extends string> = N extends simpleNum ? G_ADD_ONE<N> :
GetEnd<N> extends '9' ? `${ADD_ONE<GetEndPre<N>>}0` :
`${GetEndPre<N>}${G_ADD_ONE<GetEnd<N>>}`;
type addOne0 = ADD_ONE<'7'>; // 8
type addOne1 = ADD_ONE<'99'>; // 100
type addOne2 = ADD_ONE<'299'>; // 300
type addOne3 = ADD_ONE<'159'>; // 160
复制代码
好起来了,到现在 重构+1完成
重构加法
既然 +1操作
都完成了,那递归 +1操作
不就可以了吗?
是可以,但是还是面临了 n次递归
,所以这里要避开递归!
怎么处理呢,跟实现 +1操作
类似,实现99加法表!
type CD_SIMPLE_ADD<X extends string, Y extends string> = X extends '' ? Y :
Y extends '' ? X :
X extends '0' ? Y :
Y extends '0' ? X :
X extends '1' ? G_ADD_ONE<Y> :
Y extends '1' ? G_ADD_ONE<X> :
X extends '2' ?
Y extends '2' ? '4' :
Y extends '3' ? '5' :
Y extends '4' ? '6' :
Y extends '5' ? '7' :
Y extends '6' ? '8' :
Y extends '7' ? '9' :
Y extends '8' ? '10' :
Y extends '9' ? '11' :
never :
X extends '3' ?
Y extends '2' ? '5' :
Y extends '3' ? '6' :
Y extends '4' ? '7' :
Y extends '5' ? '8' :
Y extends '6' ? '9' :
Y extends '7' ? '10' :
Y extends '8' ? '11' :
Y extends '9' ? '12' :
never :
X extends '4' ?
Y extends '2' ? '6' :
Y extends '3' ? '7' :
Y extends '4' ? '8' :
Y extends '5' ? '9' :
Y extends '6' ? '10' :
Y extends '7' ? '11' :
Y extends '8' ? '12' :
Y extends '9' ? '13' :
never :
X extends '5' ?
Y extends '2' ? '7' :
Y extends '3' ? '8' :
Y extends '4' ? '9' :
Y extends '5' ? '10' :
Y extends '6' ? '11' :
Y extends '7' ? '12' :
Y extends '8' ? '13' :
Y extends '9' ? '14' :
never :
X extends '6' ?
Y extends '2' ? '8' :
Y extends '3' ? '9' :
Y extends '4' ? '10' :
Y extends '5' ? '11' :
Y extends '6' ? '12' :
Y extends '7' ? '13' :
Y extends '8' ? '14' :
Y extends '9' ? '15' :
never :
X extends '7' ?
Y extends '2' ? '9' :
Y extends '3' ? '10' :
Y extends '4' ? '11' :
Y extends '5' ? '12' :
Y extends '6' ? '13' :
Y extends '7' ? '14' :
Y extends '8' ? '15' :
Y extends '9' ? '16' :
never :
X extends '8' ?
Y extends '2' ? '10' :
Y extends '3' ? '11' :
Y extends '4' ? '12' :
Y extends '5' ? '13' :
Y extends '6' ? '14' :
Y extends '7' ? '15' :
Y extends '8' ? '16' :
Y extends '9' ? '17' :
never :
X extends '9' ?
Y extends '2' ? '11' :
Y extends '3' ? '12' :
Y extends '4' ? '13' :
Y extends '5' ? '14' :
Y extends '6' ? '15' :
Y extends '7' ? '16' :
Y extends '8' ? '17' :
Y extends '9' ? '18' :
never : never;
复制代码
加法的逻辑是:
同样根据递归数字长度来实现任意数对位的加法
复制代码
type ADD_Check<X extends string, Y extends string> = X extends simpleNum ?
Y extends simpleNum ?
CD_SIMPLE_ADD<X, Y> : ADD_ALL<X, Y> : ADD_ALL<X, Y>;
type ADD_ALL<
X extends string,
Y extends string,
// 储存结果
Z extends string = '',
// 是否进位,'1'为进位,'0'为不进位
pre extends string = '0',
// 计算新一轮的值
data extends string = CD_SIMPLE_ADD<GetEnd<X>, GetEnd<Y>>,
// 新一轮的值 + 进位
preData extends string = ADD_Check<data, pre>,
// 为了当 x 或者 y 的为空的时候导出,['data']
Q extends string = `${X}${Y}`
> = {
['loop']: ADD_ALL<
X extends '' ? '' : GetEndPre<X>,
Y extends '' ? '' : GetEndPre<Y>,
preData extends simpleNum ?
`${preData}${Z}` :
`${GetEnd<preData>}${Z}`,
preData extends simpleNum ? '0' : '1'
>;
['data']: `${ADD_Check<Q, pre>}${Z}`;
['result']: pre extends '1' ? `1${Z}`: Z;
}[X extends '' ? Y extends '' ? 'result' : 'data' : 'loop'];
type addall1 = ADD_Check<'111', '999'>; // 1110
type addall2 = ADD_Check<'555', '445'>; // 1000
type addall3 = ADD_Check<'1123', '456'>; // 1579
复制代码
实现斐波那契的推算
加法已经重构完成,那么递归加法就可以写出斐波那契函数了!
type FIB2<
T extends string,
A extends string = '0',
B extends string = '1',
N extends string = '1'
> = T extends '0' | '1' ? T :
{
['loop']: FIB2<T, B, ADD_Check<A, B>, ADD_ONE<N>>;
['result']: B;
}[T extends N ? 'result' : 'loop'];
type FIv0 = FIB2<'0'> // 0
type FIv1 = FIB2<'1'>; // 1
type FIv2 = FIB2<'2'>; // 1
type FIv3 = FIB2<'3'>; // 2
type FIv4 = FIB2<'4'>; // 3
type FIv5 = FIB2<'5'>; // 5
type FIv6 = FIB2<'6'>; // 8
type FIv7 = FIB2<'7'>; // 13
type FIv8 = FIB2<'8'>; // 21
type FIv9 = FIB2<'9'>; // 34
type FIv10 = FIB2<'10'>; // 55
type FIv11 = FIB2<'11'>; // 89
type FIv12 = FIB2<'12'>; // 144
type FIv22 = FIB2<'22'>; // 17711
type FIv23 = FIB2<'23'>; // 28657
type FIv24 = FIB2<'24'>; // 46368
type FIv25 = FIB2<'25'>; // 75025
type FIv26 = FIB2<'26'>; // 121393
type FIv27 = FIB2<'27'>; // 196418
type FIv28 = FIB2<'28'>; // 317811
type FIv33 = FIB2<'33'>; // 3524578
type FIv42 = FIB2<'42'>; // 267914296
复制代码
可能有人会问,为啥到42位就不举例了,因为到43位电脑又罢工了!
真是头疼啊,这个问题留着下次优化吧~
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END