大家好,我是苏先生,2024年我的第一愿景就是做一个可行的副业,求大佬带我~~
好文推荐
前言
前边几篇文章我们一共实现了43 个工具类型,按照本专栏的规划,还差56个...
本节我们继续学习一个新的工具类型
提示
对于语法层面的知识点本系列(类型体操开头的标题)不会展开说明哈,可以自行搜索学习其他大佬的优质文章或者等我后续更新补充
题目
实现
首先,使用type关键字创建类型Fibonacci,它接收一个数值参数T
ts
type Fibonacci<T extends number>
由于斐波那契序列一般指的都是非负整数索引,因此对于泛型T,需要对其取绝对值。至于负数,其本质上等价于先取正整数的斐波那契数然后再对其取反即可
如下,当为负数时,先通过Abs取正,再通过模版字符类型取反
ts
type Fibonacci<T extends number> =
T extends Abs<T>
?
_Fibonacci<T>
:
`-${_Fibonacci<Abs<T>>}`
不过,为了返回类型的一致性,将正整数T对应的斐波那契数也转换成字符串类型
ts
type Fibonacci<T extends number> =
T extends Abs<T>
?
`${_Fibonacci<T>}`
:
`-${_Fibonacci<Abs<T>>}`
另外
已知斐波那契序列的性质如下
text
f(n)=f(n-2)+f(n-1)
我们搞一个js函数来观察下
当n为0时其结果为0,当n为1或2的时候,其结果为1,这些结果是恒定的,可以将其前置处理掉
ts
type _Fibonacci<T extends number> =
T extends 0
?
0
:
T extends 1 | 2
?
1
:
...
省略号部分即T>=3的时候,由截图可知,它对应的斐波那契数为
text
f(3)=f(1)+f(2)
则,取parent的首字母P为f(2),即f(n-1),grandfather的首字母G为f(1),即f(n-2),声明变量如下
ts
type _Fibonacci<
T extends number,
P extends number[] = [1],
G extends number[] = [1]
> = ...
则对于大于等于3的数,只需要对其执行递归
ts
_Fibonacci<T,f(n-1),f(n-2)>
然后取P和G的length和就是最终的答案了
ts
[...P,...G]['length']
那现在有两个问题需要解决
1.递归何时结束?
声明变量I表示当前正在计算的斐波那契数
ts
type _Fibonacci<
...,
I extends number[] = [1,1,1],
...> = ...
每递归一次,就将I的length加1
ts
_Fibonacci<...,[...I,1],...>
当I['length']与T相等时,递归结束
ts
type _Fibonacci<
...,
I extends number[] = [1,1,1],
...>
=
...
I['length'] extends T
?
'出口'
:
'递归'
2.传入递归的f(n-1)和f(n-2)是什么?
结合定义和前文关于出口的说明,只需要依次向前推进一位即可
即
当T=6时
进入递归,P为5即f(n-1),G为4即f(n-2)
ts
_Fibonacci<T,f(6),f(5)>
当T=7时
进入递归,P为6即f(n-1),G为5即f(n-2)
ts
_Fibonacci<T,f(7),f(6)>
故,完整实现如下
ts
type Abs<
N extends number
> =
`${N}`
extends `-${infer R extends number}`
? R
: N;
type _Fibonacci<
T extends number,
I extends number[] = [1,1,1],
P extends number[] = [1],
G extends number[] = [1]
> =
T extends 0
?
0
:
T extends 1 | 2
?
1
:
T extends I['length']
?
[...P,...G]['length']
:
_Fibonacci<T,[...I,1],[...P,...G],P>
type Fibonacci<T extends number> =
T extends Abs<T>
?
`${_Fibonacci<T>}`
:
`-${_Fibonacci<Abs<T>>}`
使用如下
下期预告
- 【知识点】巧用装饰器自动修正TypeScript中的类this指向
-【类型体操】去除数组指定元素
接收数组类型的 T 和数字或数组类型的 U 为参数,会返回一个去除 U 中元素的数组 T
ts
type Res = Without<[1, 2], 1>; // [2]
type Res1 = Without<[1, 2, 4, 1, 5], [1, 2]>; // [4, 5]
type Res2 = Without<[2, 3, 2, 3, 2, 3, 2, 3], [2, 3]>; // []
如果本文对您有用,希望能得到您的点赞和收藏
订阅专栏 ,每月更新1-2篇类型体操,等你哟😎