您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關TypeScript中怎么實現一個斐波那契數列,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
const fib = (n: number): number => n <= 1 ? n : fib(n - 1) + fib(n - 2); for (let i = 0; i < 10; i++) { console.log(i, fib(i)); }
運行結果如下:
斐波那契數列打印結果
程序完全沒問題,完結撒花!
開玩笑的,上面是只一個用了TypeScript類型定義的JavaScript寫法,我們其實真正想這樣做↓↓↓, 也就是使用TS Type解決FIbonacci
import { Fib, Add } from './fib-type'; type one = Fib<1>; type zero = Fib<0>; type Two = Add<one, one>; type Five = Add<Two, Add<Two, one>>; type Fib5 = Fib<Five>; type Fib9 = Fib<9>; type r0 = Fib<Zero>; // type r0= 0 type r1 = Fib<One>; // type r1 = 1 type r2 = Fib<Two>; // type r2 = 1 type r3 = Fib<3>; // type r3 = 2 type r4 = Fib<4>; // type r4 = 3 type r5 = Fib<5>; // type r5 = 5 type r6 = Fib<6>; // type r6 = 8 type r9 = Fib<9>; // type r9 = 34 type sum = Add<r9, r6>; // type sum = 42
類型提示
要想實現斐波那契數列,參考一開始的代碼,有基本的比較, 加法, 循環語法, 所以我們也需要使用類型系統依次實現這三種功能
為了實現加法, 需要先實現一些工具類型
// 元組長度 type Length<T extends any[]> = T['length']; type one = 1 // 使用extends實現數字相等的比較 type a111 = 0 extends one ? true : false // type a111 = false type a112 = 1 extends one ? true : false // type a112 = true
range的實現是遞歸實現的
// 偽代碼 function range(n, list=[]){ if(n<=0) return list.length return range(n-1, [1, ...list]) }
TypeScript的限制, 沒有循環, 只能用遞歸代替循環, 后面會有幾個類似的寫法, 記住一點:遞歸有幾個出口, 對象就有幾個 key, 每個 key 就是一個條件
// 創建指定長度的元組, 用第二個參數攜帶返回值 type Range<T extends Number = 0, P extends any[] = []> = { 0: Range<T, [any, ...P]>; 1: P; }[Length<P> extends T ? 1 : 0]; // 拼接兩個元組 type Concat<T extends any[], P extends any[]> = [...T, ...P]; type t1 = Range<3>; // type t1 = [any, any, any] type Zero = Length<Range<0>>; // type Zero = 0 type Ten = Length<Range<10>>; // type Ten = 10 type Five = Length<Range<5>>; // type Five = 5 type One = Length<Range<1>>;
有了上面的工具語法,那么實現加法就比較容易了, 只需要求兩個元組合并后的長度
type Add<T extends number, P extends number> = Length< Concat<Range<T>, Range<P>> >; type Two = Add<One, One>; // type Two = 2 type Three = Add<One, Two>; // type Three = 3
有了加法,該如何實現減法呢?一般減法和除法都比加法難, 所以我們需要更多的工具類型函數!
2.2.1 實現一些基本工具類型
Shift:刪除第一個元素
Append:在元組末尾插入元素
IsEmpty / NotEmpty:判斷列表為空
// 去除元組第一個元素 [1,2,3] -> [2,3] type Shift<T extends any[]> = ((...t: T) => any) extends ( _: any, ...Shift: infer P ) => any ? P : []; type pp = Shift<[number, boolean,string, Object]> // type pp = [boolean, string, Object] // 向元組中追加 type Append<T extends any[], E = any> = [...T, E]; type IsEmpty<T extends any[]> = Length<T> extends 0 ? true : false; type NotEmpty<T extends any[]> = IsEmpty<T> extends true ? false : true; type t4 = IsEmpty<Range<0>>; // type t4 = true type t5 = IsEmpty<Range<1>>; // type t5 = false
2.2.2 邏輯類型
And:a && b
// 邏輯操作 type And<T extends boolean, P extends boolean> = T extends false ? false : P extends false ? false : true; type t6 = And<true, true>; // type t6 = true type t7 = And<true, false>; // type t7 = false type t8 = And<false, false>; // type t8 = false type t9 = And<false, true>; // type t9 = false
2.2.3 小于等于
偽代碼: 主要思想是同時從列表中取出一個元素, 長度先到0的列表比較短
function dfs (a, b){ if(a.length && b.length){ a.pop() b.pop() return dfs(a,b) }else if(a.length){ a >= b }else if (b.length){ b > a } }
思想:將數字的比較轉換為列表長度的比較
// 元組的小于等于 T <= P, 同時去除一個元素, 長度先到0的比較小 type LessEqList<T extends any[], P extends any[]> = { 0: LessEqList<Shift<T>, Shift<P>>; 1: true; 2: false; }[And<NotEmpty<T>, NotEmpty<P>> extends true ? 0 : IsEmpty<T> extends true ? 1 : 2]; // 數字的小于等于 type LessEq<T extends number, P extends number> = LessEqList<Range<T>, Range<P>>; type t10 = LessEq<Zero, One>; // type t10 = true type t11 = LessEq<One, Zero>; // type t11 = false type t12 = LessEq<One, One>; // type t12 = true
減法有兩個思路,列表長度相減求值和數字相減求值
2.3.1 列表減法
默認大減小, 小減大只需要判斷下反著來, 然后加個符號就行了, 這里為了簡單沒有實現,可參考偽代碼如下:
// 偽代碼 const a = [1, 2, 3]; const b = [4, 5]; const c = []; while (b.length !== a.length) { a.pop(); c.push(1); }// c.length === a.length - b.lengthconsole.log(c.length); // 元組的減法 T - P, 同時去除一個元素, 長度到0時, 剩下的就是結果, 這里使用第三個參數來攜帶結果, 每次做一次減法, 向第三個列表里面追加 type SubList<T extends any[], P extends any[], R extends any[] = []> = { 0: Length<R>; 1: SubList<Shift<T>, P, Apped<R>>; }[Length<T> extends Length<P> ? 0 : 1]; type t13 = SubList<Range<10>, Range<5>>; // type t13 = 5
2.3.2 數字減法
思想:將數字轉成元組后再比較
// 集合大小不能為負數, 默認大減小 // 數字的減法 type Sub<T extends number, P extends number> = { 0: Sub<P, T>; 1: SubList<Range<T>, Range<P>>; }[LessEq<T, P> extends true ? 0 : 1]; type t14 = Sub<One, Zero>; // type t14 = 1 type t15 = Sub<Ten, Five>; // type t15 = 5
我們有了這些工具后, 就可以將一開始用JavaScript實現的斐波那契數列的實現代碼,翻譯為TypeScript類型編碼
在JavaScript中,我們使用函數
const fib = (n: number): number => n <= 1 ? n : fib(n - 1) + fib(n - 2);
在TypeScript中,我們使用類型, 其實只是換了一種寫法, 用類型函數描述運算, 萬變不離其宗~
由于TypeScript遞歸限制, 并不能求解非常大的項, 不過好玩就完事了~
export type Fib<T extends number> = { 0: T; 1: Add<Fib<Sub<T, One>>, Fib<Sub<T, Two>>>; }[LessEq<T, One> extends true ? 0 : 1]; type r0 = Fib<Zero>; // type r10= 0 type r1 = Fib<One>; // type r1 = 1 type r2 = Fib<Two>; // type r2 = 1 type r3 = Fib<3>; // type r3 = 2 type r4 = Fib<4>; // type r4 = 3 type r5 = Fib<5>; //type r5 = 5 type r6 = Fib<6>; // type r6 = 8
關于TypeScript中怎么實現一個斐波那契數列就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。