当前位置: 首页 > 科技观察

用TypeScript类型系统编程实现斐波那契数列

时间:2023-03-19 18:05:02 科技观察

转载本文请联系DYBOY公众号。作为前端开发者,你一定知道在项目中经常使用TypeScript做类型约束,使得JavaScript这种弱类型语言具备静态检查能力,也促进了前端工程的进化。在学习和学习TypeScript的过程中,小伙伴发现了TS的一些有趣的功能,于是把这篇文章分享给大家。朋友(于浩)的原文可能比较难懂。笔者已经尝试添加了一些说明,但想要彻底领悟TS“体操”的奥妙,还是得自己去实践。1.我们要做的我们的目的是通过TypeScript的类型声明语法编写一个斐波那契数列算法。也就是说,类似于利用现有的机器码转指令集、二进制转十进制、汇编语言转高级程序设计语言的过程,类型定义语法也可以实现编程。最后我们要实现的斐波那契数列代码是这??样的?constfib=(n:number):number=>n<=1?n:fib(n-1)+fib(n-2);for(leti=0;i<10;i++){console.log(i,fib(i));}运行结果如下:斐波那契数列打印结果程序完全没问题,花完了!开个玩笑,以上只是一种使用TypeScript类型定义的JavaScript写法,我们其实很想做这个↓↓↓,也就是用TS类型来解决FIbonacciimport{Fib,Add}from'./fib-type';typeone=Fib<1>;typezero=Fib<0>;typeTwo=Add;typeFive=Add>;typeFib5=Fib;typeFib9=Fib<9>;typer0=Fib;//typer0=0typer1=Fib;//typer1=1typer2=Fib;//typer2=1typer3=Fib<3>;//typer3=2typer4=Fib<4>;//typer4=3typer5=Fib<5>;//typer5=5typer6=Fib<6>;//typer6=8typer9=Fib<9>;//typer9=34typesum=Add;//typesum=42typeprompt2.我们应该怎么做要实现斐波那契数列,参考一开始的代码,有基本的比较,加法,循环语法,所以我们还需要使用类型系统来实现这三个函数依次2.1加法的实现为了实现加法,我们需要先实现一些工具类型//元组长度typeLength=T['length'];typeone=1//使用extendsto交流电hieve数字相等比较typea111=0extendsone?true:false//typea111=falsetypea112=1extendsone?true:false//typea112=truerange递归实现//伪代码functionrange(n,list=[]){if(n<=0)returnlist.lengthreturnrange(n-1,[1,...list])}TypeScript的局限,没有循环,只能用递归代替循环,后面会有几种类似的写法,记住一件事:递归有几个出口,对象有几个键,每个键是一个condition//创建指定长度的元组,使用第二个参数携带返回值typeRange={0:Range;1:P;}[Length

extendsT?1:0];//两个元组的拼接typeConcat=[...T,...P];typet1=Range<3>;//typet1=[any,any,any]typeZero=Length>;//typeZero=0typeTen=Length>;//typeTen=10typeFive=Length>;//typeFive=5typeOne=长度>;有了上面的工具语法,实现加法就更简单了,只需要两个元组组合的长度typeAdd=Length,Range

>>;typeTwo=Add;//typeTwo=2typeThree=Add;//typeThree=3有了加法,如何实现减法呢?一般来说,减法和除法比加法难,所以我们需要更多的工具类函数!2.2工具功能2.2.1实现一些基本工具类型Shift:删除第一个元素Append:在元组末尾插入一个元素IsEmpty/NotEmpty:判断列表为空//移除元组第一个元素[1,2,3]->[2,3]typeShift=((...t:T)=>any)extends(_:any,...Shift:inferP)=>any?P:[];typepp=Shift<[number,boolean,string,Object]>//typepp=[boolean,string,Object]//追加typeAppend=[...T,E];typeIsEmpty=Length到tupleextends0?true:false;typeNotEmpty=IsEmptyextendstrue?false:true;typet4=IsEmpty>;//typet4=truetypet5=IsEmpty>;//typet5=false2.2.2逻辑类型And:a&&b//逻辑运算typeAnd=Textendsfalse?false:Pextendsfalse?false:true;typet6=And;//typet6=truetypet7=And;//typet7=falsetypet8=And;//typet8=falsetypet9=And;//typet9=false2.2.3小于等于伪代码:主要思想是同时从列表中取出一个元素,列表w软管长度最先到达0时更短functiondfs(a,b){if(a.length&&b.length){a.pop()b.pop()returndfs(a,b)}elseif(a.length){a>=b}elseif(b.length){b>a}}思路:将数字的比较转换为列表长度的比较//tuple小于等于T<=P,同时移除一个元素,长度先到0的更小typeLessEqList={0:LessEqList,Shift

>;1:true;2:false;}[And,NotEmpty

>extendstrue?0:IsEmptyextendstrue?1:2];//数字小于等于typeLessEq=LessEqList,Range

>;typet10=LessEq;//typet10=truetypet11=LessEq;//typet11=falsetypet12=LessEq;//typet12=true2.3减法的实现减法有两种思路,列表长度减法求值和数减法求值2.3.1列表减法默认大减法,小减法只需要判断和取反,然后加法一个符号,这里为了简单就不实现了,可以参考伪代码如下://伪代码consta=[1,2,3];constb=[4,5];constc=[];while(b.length!==a.length){a.pop();c.push(1);}//c.length===a.length-b.lengthconsole.log(c.length);//元组减法T-P,同时移除当一个元素的长度达到0时,剩下的就是结果。这里用第三个参数来携带结果,每次做减法,typeSubList={0:Length;1:SubList,P,Apped>;}[LengthextendsLength

?0:1];typet13=SubList,Range<5>>;//typet13=52.3.2数字减法的思路:把数字转成元组再比较//集合的大小不能为负数,默认大减//数字减法typeSub={0:Sub;1:SubList,Range

>;}[LessEqextendstrue?0:1];typet14=Sub;//typet14=1typet15=Sub;//typet15=5有了这些工具后,我们就可以将JavaScript中实现的斐波那契数列的实现代码翻译成TypeScript类型编码3.fib:JS函数-->TS类型在JavaScript中,我们使用函数constfib=(n:number):number=>n<=1?n:fib(n-1)+fib(n-2);在TypeScript中,我们使用类型,其实只是改变了一种写法,用类型函数来描述操作,始终不变。由于TypeScript的递归限制,无法解决非常大的项目,不过很好玩,就结束了。exporttypeFib={0:T;1:Add>,Fib>>;}[LessEqextendstrue?0:1];typer0=Fib;//typer10=0typer1=Fib;//typer1=1typer2=Fib;//typer2=1typer3=Fib<3>;//typer3=2typer4=Fib<4>;//typer4=3typer5=Fib<5>;//typer5=5typer6=Fib<6>;//typer6=8最后再推荐一些其他比较有意思的项目:《TypeScript类型元编程:实现8位数的算术运算》-https://zhuanlan.zhihu.com/p/85655537《TypeScript 4.1 新特性:字符串模板类型,Vuex 终于有救了?》-https://juejin.cn/post/6867785919693832200《Ts 类型系统实现线性查找》-https://bytedance.feishu.cn/docs/doccney0oWRZMSM1w9e0izshW5d四、总结阅读T??ypeScript实现FeiBonacci序列的这组操作是否能让你回到“实现流水线CPU”的实验室时光?近几十年来IT发展迅速,越来越多的“程序员”加入了互联网行业,在一些高级语言和开发框架下,“程序员”在编码时只需要专注于业务逻辑的实现。很少有人会关注计算机底层是如何实现加减乘除的。当然,社会在进步,科技也在日新月异。周而复始,时不时地停下来,回忆一下自己第一次接触计算机编程,输出第一行“HelloWorld!”时的喜悦。命令行上的代码,也许那是我们回不去的青春……