TypeScript类型体操--斐波那契序列

大家好,我是苏先生,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篇类型体操,等你哟😎

相关推荐
struggle202510 小时前
AxonHub 开源程序是一个现代 AI 网关系统,提供统一的 OpenAI、Anthropic 和 AI SDK 兼容 API
css·人工智能·typescript·go·shell·powershell
执剑、天涯15 小时前
通过一个typescript的小游戏,使用单元测试实战(二)
javascript·typescript·单元测试
chéng ௹17 小时前
Vue3+Ts+Element Plus 权限菜单控制节点
前端·javascript·vue.js·typescript
武清伯MVP2 天前
阮一峰《TypeScript 教程》学习笔记——基本用法
笔记·学习·typescript
ttod_qzstudio3 天前
解决 Vue 3 + TypeScript 中 v-for 循环类型推断问题
前端·vue.js·typescript
今天头发还在吗3 天前
【React】动态SVG连接线实现:图片与按钮的可视化映射
前端·javascript·react.js·typescript·前端框架
冷冷的菜哥3 天前
react多文件分片上传——支持拖拽与进度展示
前端·react.js·typescript·多文件上传·分片上传
Kisang.4 天前
【HarmonyOS】窗口管理实战指南
前端·华为·typescript·harmonyos·鸿蒙
Dajiaonew4 天前
Vue3 + TypeScript 一篇文章 后端变全栈
前端·javascript·typescript
敲敲敲敲暴你脑袋4 天前
用3Dmol.js展示3D分子结构
typescript·webgl·数据可视化