成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

TypeScript 類型體操:數組長度實現數值運算

開發 前端
TypeScript 類型系統不是圖靈完備,各種邏輯都能寫么,但好像沒發現數值相關的邏輯。

本文轉載自微信公眾號「神光的編程秘籍」,作者神說要有光。轉載本文請聯系神光的編程秘籍公眾號。

TS 類型體操小冊掘金排期到 4月份了,有點晚。。。

所以,我把其中一個套路提出來作為文章發了,大家可以提前感受下,到時候也會設置為小冊的試讀章節。

這個套路叫做數組長度做計數,就是用數組長度實現加減乘除、各種計數,是六大套路里最騷的一個。

下面是正文(小冊原文):

套路四:數組長度做計數

TypeScript 類型系統不是圖靈完備,各種邏輯都能寫么,但好像沒發現數值相關的邏輯。

沒錯,數值相關的邏輯比較繞,被我單獨摘了出來,就是這節要講的內容。

這是類型體操的第四個套路:數組長度做計數。

數組長度做計數

TypeScript 類型系統沒有加減乘除運算符,怎么做數值運算呢?

不知道大家有沒有注意到數組類型取 length 就是數值。

比如:

而數組類型我們是能構造出來的,那么通過構造不同長度的數組然后取 length,不就是數值的運算么?

TypeScript 類型系統中沒有加減乘除運算符,但是可以通過構造不同的數組然后取 length 的方式來完成數值計算,把數值的加減乘除轉化為對數組的提取和構造。

這點可以說是類型體操中最麻煩的一個點,需要思維做一些轉換,繞過這個彎來。

下面我們就來做一些真實的案例來掌握它吧。

數組長度實現加減乘除

Add

我們知道了數值計算要轉換為對數組類型的操作,那么加法的實現很容易想到:

構造兩個數組,然后合并成一個,取 length。

比如 3 + 2,就是構造一個長度為 3 的數組類型,再構造一個長度為 2 的數組類型,然后合并成一個數組,取 length。

構造多長的數組是不確定的,需要遞歸構造,這個我們實現過:

type BuildArray<
Length extends number,
Ele = unknown,
Arr extends unknown[] = []
> = Arr['length'] extends Length
? Arr
: BuildArray<Length, Ele, [...Arr, Ele]>;

類型參數 Length 是要構造的數組的長度。類型參數 Ele 是數組元素,默認為 unknown。類型參數 Arr 為構造出的數組,默認是 []。

如果 Arr 的長度到達了 Length,就返回構造出的 Arr,否則繼續遞歸構造。

構造數組實現了,那么基于它就能實現加法:

type Add<Num1 extends number, Num2 extends number> = 
[...BuildArray<Num1>,...BuildArray<Num2>]['length'];

我們拿大一點的數測試下:

結果是對的。

就這樣,我們通過構造一定長度的數組取 length 的方式實現了加法運算。

Subtract

加法是構造數組,那減法怎么做呢?

減法是從數值中去掉一部分,很容易想到可以通過數組類型的提取來做。

比如 3 是 [unknown, unknown, unknown] 的數組類型,提取出 2 個元素之后,剩下的數組再取 length 就是 1。

所以減法的實現是這樣的:

type Subtract<Num1 extends number, Num2 extends number> = 
BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest]
? Rest['length']
: never;

類型參數 Num1、Num2 分別是被減數和減數,通過 extends 約束為 number。

構造 Num1 長度的數組,通過模式匹配提取出 Num2 長度個元素,剩下的放到 infer 聲明的局部變量 Rest 里。

取 Rest 的長度返回,就是減法的結果。

就這樣,我們通過數組類型的提取實現了減法運算。

Multiply

我們把加法轉換為了數組構造,把減法轉換為了數組提取。那乘法怎么做呢?

為了解釋乘法,我去翻了下小學教材,找到了這樣一張圖:

1 乘以 5 就相當于 1 + 1 + 1 + 1 + 1,也就是說乘法就是多個加法結果的累加。

那么我們在加法的基礎上,多加一個參數來傳遞中間結果的數組,算完之后再取一次 length 就能實現乘法:

type Mutiply<
Num1 extends number,
Num2 extends number,
ResultArr extends unknown[] = []
> = Num2 extends 0 ? ResultArr['length']
: Mutiply<Num1, Subtract<Num2, 1>, [...BuildArray<Num1>, ...ResultArr]>;

類型參數 Num1 和 Num2 分別是被加數和加數。

因為乘法是多個加法結果的累加,我們加了一個類型參數 ResultArr 來保存中間結果,默認值是 [],相當于從 0 開始加。

每加一次就把 Num2 減一,直到 Num2 為 0,就代表加完了。

加的過程就是往 ResultArr 數組中放 Num1 個元素。

這樣遞歸的進行累加,也就是遞歸的往 ResultArr 中放元素。

最后取 ResultArr 的 length 就是乘法的結果。

就這樣,我們通過遞歸的累加實現了乘法。

Divide

乘法是遞歸的累加,那減法不就是遞歸的累減么?

我再去翻了下小學教材,找到了這樣一張圖:

我們有 9 個蘋果,分給美羊羊 3 個,分給懶羊羊 3 個,分給沸羊羊 3 個,最后剩下 0 個。所以 9 / 3 = 3。

所以,除法的實現就是被減數不斷減去減數,直到減為 0,記錄減了幾次就是結果。

也就是這樣的:

type Divide<
Num1 extends number,
Num2 extends number,
CountArr extends unknown[] = []
> = Num1 extends 0 ? CountArr['length']
: Divide<Subtract<Num1, Num2>, Num2, [unknown, ...CountArr]>;

類型參數 Num1 和 Num2 分別是被減數和減數。

類型參數 CountArr 是用來記錄減了幾次的累加數組。

如果 Num1 減到了 0 ,那么這時候減了幾次就是除法結果,也就是 CountArr['length']。

否則繼續遞歸的減,讓 Num1 減去 Num2,并且 CountArr 多加一個元素代表又減了一次。

這樣就實現了除法:

就這樣,我們通過遞歸的累減并記錄減了幾次實現了除法。

做完了加減乘除,我們再來做一些別的數值計算的類型體操。

數組長度實現計數

StrLen

數組長度可以取 length 來得到,但是字符串類型不能取 length,所以我們來實現一個求字符串長度的高級類型。

字符串長度不確定,明顯要用遞歸。每次取一個并計數,直到取完,就是字符串長度。

type StrLen<
Str extends string,
CountArr extends unknown[] = []
> = Str extends `${string}${infer Rest}`
? StrLen<Rest, [...CountArr, unknown]>
: CountArr['length']

類型參數 Str 是待處理的字符串。類型參數 CountArr 是做計數的數組,默認值 [] 代表從 0 開始。

每次通過模式匹配提取去掉一個字符之后的剩余字符串,并且往計數數組里多放入一個元素。遞歸進行取字符和計數。

如果模式匹配不滿足,代表計數結束,返回計數數組的長度 CountArr['length']。

這樣就能求出字符串長度:

GreaterThan

能夠做計數了,那也就能做兩個數值的比較。

我們往一個數組類型中不斷放入元素取長度,如果先到了 A,那就是 B 大,否則是 A 大:

type GreaterThan<
Num1 extends number,
Num2 extends number,
CountArr extends unknown[] = []
> = Num1 extends Num2
? false
: CountArr['length'] extends Num2
? true
: CountArr['length'] extends Num1
? false
: GreaterThan<Num1, Num2, [...CountArr, unknown]>;

類型參數 Num1 和 Num2 是待比較的兩個數。

類型參數 CountArr 是計數用的,會不斷累加,默認值是 [] 代表從 0 開始。

如果 Num1 extends Num2 成立,代表相等,直接返回 false。

否則判斷計數數組的長度,如果先到了 Num2,那么就是 Num1 大,返回 true。

反之,如果先到了 Num1,那么就是 Num2 大,返回 false。

如果都沒到就往計數數組 CountArr 中放入一個元素,繼續遞歸。

這樣就實現了數值比較。

當 3 和 4 比較時:

當 6 和 4 比較時:

Fibonacci談到了數值運算,就不得不提起經典的 Fibonacci 數列的計算。

Fibonacci

數列是 1、1、2、3、5、8、13、21、34、…… 這樣的數列,有當前的數是前兩個數的和的規律。

F(0) = 1,F(1) = 1, F(n) = F(n - 1) + F(n - 2)(n ≥ 2,n ∈ N*)

也就是遞歸的加法,在 TypeScript 類型編程里用構造數組來實現這種加法:

type FibonacciLoop<
PrevArr extends unknown[],
CurrentArr extends unknown[],
IndexArr extends unknown[] = [],
Num extends number = 1
> = IndexArr['length'] extends Num
? CurrentArr['length']
: FibonacciLoop<CurrentArr, [...PrevArr, ...CurrentArr], [...IndexArr, unknown], Num>

type Fibonacci<Num extends number> = FibonacciLoop<[1], [], [], Num>;

類型參數 PrevArr 是代表之前的累加值的數組。類型參數 CurrentArr 時代表當前數值的數組。

類型參數 IndexArr 用于記錄 index,每次遞歸加一,默認值是 [],代表從 0 開始。

類型參數 Num 代表求數列的第幾個數。

判斷當前 index 也就是 IndexArr['length'] 是否到了 Num,到了就返回當前的數值 CurrentArr['length']。

否則求出當前 index 對應的數值,用之前的數加上當前的數 [...PrevArr, ... CurrentArr]。

然后繼續遞歸,index + 1,也就是 [...IndexArr, unknown]。

這就是遞歸計算 Fibinacci 數列的數的過程。

可以正確的算出第 8 個數是 21:

總結

TypeScript 類型系統沒有加減乘除運算符,所以我們通過數組類型的構造和提取,然后取長度的方式來實現數值運算。

我們通過構造和提取數組類型實現了加減乘除,也實現了各種計數邏輯。

用數組長度做計數這一點是 TypeScript 類型體操中最麻煩的一個點,也是最容易讓新手困惑的一個點。


責任編輯:武曉燕 來源: 神光的編程秘籍
相關推薦

2022-09-20 14:43:55

TypeScript類型體操

2021-12-10 08:21:15

TypeScript高級類型類型體操

2022-03-09 20:18:49

TypeScript類型函數

2022-05-04 09:02:41

TypeScript類型工具

2022-04-11 08:42:09

TypeScript子類型定義

2025-04-10 05:00:00

JavaScriptReactWeb

2022-09-14 15:24:57

typescript快排

2021-06-09 07:55:19

Typescript類型檢查

2021-12-25 22:29:31

類型編程Javascript類型體操

2023-05-15 15:44:02

JavaScript數值存儲

2025-02-14 08:26:47

TypeScripDeepSeek

2024-03-04 06:40:49

工具類型TypeScripDeepPick

2024-02-19 10:24:32

Chainable工具類型類型體操

2021-06-05 21:30:24

typescriptOverride檢查

2022-02-25 09:06:02

TypeScripnever工具

2009-10-09 14:55:02

VB.NET數組

2021-07-27 06:06:34

TypeScript語言運算符

2020-09-17 17:53:12

面試ArrayList數組

2024-05-11 10:19:31

TypeScript類型接口

2021-08-18 07:56:05

Typescript類型本質
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: aa级毛片毛片免费观看久 | 一区视频在线 | 亚洲成人日韩 | 久久亚洲一区二区三区四区 | 中国黄色毛片视频 | 国产一级视频在线播放 | 精品久久久久久红码专区 | 天堂在线www | 爱爱免费视频 | 国产精品96久久久久久 | 国产一区二区三区免费视频 | 一级片子| 四虎影院免费在线 | a级片在线观看 | 欧美激情精品久久久久 | 蜜臀网 | 天天爽天天操 | www.一区二区 | 黄色免费网站在线看 | 国产午夜三级一区二区三 | 日日摸天天添天天添破 | 国产精品国产精品国产专区不卡 | 久久久精彩视频 | 涩涩导航 | 成人免费久久 | www.伊人.com | 亚洲欧美日韩精品 | 爱爱免费视频网站 | 中文字幕黄色大片 | 欧美中文字幕一区二区 | 久久伊| 久久天堂网 | 欧美一级视频在线观看 | 精品日韩一区 | 久久久久国产一区二区三区四区 | 免费久久精品视频 | 美日韩免费视频 | 国产乱码精品一品二品 | 亚洲美女网站 | 成人av在线网站 | 国产免费一区二区三区 |