日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
TypeScript類型體操:數(shù)組長度實(shí)現(xiàn)數(shù)值運(yùn)算

TS 類型體操小冊(cè)掘金排期到 4月份了,有點(diǎn)晚。。。

創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供瑯琊網(wǎng)站建設(shè)、瑯琊做網(wǎng)站、瑯琊網(wǎng)站設(shè)計(jì)、瑯琊網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、瑯琊企業(yè)網(wǎng)站模板建站服務(wù),10多年瑯琊做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

所以,我把其中一個(gè)套路提出來作為文章發(fā)了,大家可以提前感受下,到時(shí)候也會(huì)設(shè)置為小冊(cè)的試讀章節(jié)。

這個(gè)套路叫做數(shù)組長度做計(jì)數(shù),就是用數(shù)組長度實(shí)現(xiàn)加減乘除、各種計(jì)數(shù),是六大套路里最騷的一個(gè)。

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

套路四:數(shù)組長度做計(jì)數(shù)

TypeScript 類型系統(tǒng)不是圖靈完備,各種邏輯都能寫么,但好像沒發(fā)現(xiàn)數(shù)值相關(guān)的邏輯。

沒錯(cuò),數(shù)值相關(guān)的邏輯比較繞,被我單獨(dú)摘了出來,就是這節(jié)要講的內(nèi)容。

這是類型體操的第四個(gè)套路:數(shù)組長度做計(jì)數(shù)。

數(shù)組長度做計(jì)數(shù)

TypeScript 類型系統(tǒng)沒有加減乘除運(yùn)算符,怎么做數(shù)值運(yùn)算呢?

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

比如:

而數(shù)組類型我們是能構(gòu)造出來的,那么通過構(gòu)造不同長度的數(shù)組然后取 length,不就是數(shù)值的運(yùn)算么?

TypeScript 類型系統(tǒng)中沒有加減乘除運(yùn)算符,但是可以通過構(gòu)造不同的數(shù)組然后取 length 的方式來完成數(shù)值計(jì)算,把數(shù)值的加減乘除轉(zhuǎn)化為對(duì)數(shù)組的提取和構(gòu)造。

這點(diǎn)可以說是類型體操中最麻煩的一個(gè)點(diǎn),需要思維做一些轉(zhuǎn)換,繞過這個(gè)彎來。

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

數(shù)組長度實(shí)現(xiàn)加減乘除

Add

我們知道了數(shù)值計(jì)算要轉(zhuǎn)換為對(duì)數(shù)組類型的操作,那么加法的實(shí)現(xiàn)很容易想到:

構(gòu)造兩個(gè)數(shù)組,然后合并成一個(gè),取 length。

比如 3 + 2,就是構(gòu)造一個(gè)長度為 3 的數(shù)組類型,再構(gòu)造一個(gè)長度為 2 的數(shù)組類型,然后合并成一個(gè)數(shù)組,取 length。

構(gòu)造多長的數(shù)組是不確定的,需要遞歸構(gòu)造,這個(gè)我們實(shí)現(xiàn)過:

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

類型參數(shù) Length 是要構(gòu)造的數(shù)組的長度。類型參數(shù) Ele 是數(shù)組元素,默認(rèn)為 unknown。類型參數(shù) Arr 為構(gòu)造出的數(shù)組,默認(rèn)是 []。

如果 Arr 的長度到達(dá)了 Length,就返回構(gòu)造出的 Arr,否則繼續(xù)遞歸構(gòu)造。

構(gòu)造數(shù)組實(shí)現(xiàn)了,那么基于它就能實(shí)現(xiàn)加法:

type Add = 
[...BuildArray,...BuildArray]['length'];

我們拿大一點(diǎn)的數(shù)測試下:

結(jié)果是對(duì)的。

就這樣,我們通過構(gòu)造一定長度的數(shù)組取 length 的方式實(shí)現(xiàn)了加法運(yùn)算。

Subtract

加法是構(gòu)造數(shù)組,那減法怎么做呢?

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

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

所以減法的實(shí)現(xiàn)是這樣的:

type Subtract = 
BuildArray extends [...arr1: BuildArray, ...arr2: infer Rest]
? Rest['length']
: never;

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

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

取 Rest 的長度返回,就是減法的結(jié)果。

就這樣,我們通過數(shù)組類型的提取實(shí)現(xiàn)了減法運(yùn)算。

Multiply

我們把加法轉(zhuǎn)換為了數(shù)組構(gòu)造,把減法轉(zhuǎn)換為了數(shù)組提取。那乘法怎么做呢?

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

1 乘以 5 就相當(dāng)于 1 + 1 + 1 + 1 + 1,也就是說乘法就是多個(gè)加法結(jié)果的累加。

那么我們?cè)诩臃ǖ幕A(chǔ)上,多加一個(gè)參數(shù)來傳遞中間結(jié)果的數(shù)組,算完之后再取一次 length 就能實(shí)現(xiàn)乘法:

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

類型參數(shù) Num1 和 Num2 分別是被加數(shù)和加數(shù)。

因?yàn)槌朔ㄊ嵌鄠€(gè)加法結(jié)果的累加,我們加了一個(gè)類型參數(shù) ResultArr 來保存中間結(jié)果,默認(rèn)值是 [],相當(dāng)于從 0 開始加。

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

加的過程就是往 ResultArr 數(shù)組中放 Num1 個(gè)元素。

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

最后取 ResultArr 的 length 就是乘法的結(jié)果。

就這樣,我們通過遞歸的累加實(shí)現(xiàn)了乘法。

Divide

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

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

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

所以,除法的實(shí)現(xiàn)就是被減數(shù)不斷減去減數(shù),直到減為 0,記錄減了幾次就是結(jié)果。

也就是這樣的:

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

類型參數(shù) Num1 和 Num2 分別是被減數(shù)和減數(shù)。

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

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

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

這樣就實(shí)現(xiàn)了除法:

就這樣,我們通過遞歸的累減并記錄減了幾次實(shí)現(xiàn)了除法。

做完了加減乘除,我們?cè)賮碜鲆恍﹦e的數(shù)值計(jì)算的類型體操。

數(shù)組長度實(shí)現(xiàn)計(jì)數(shù)

StrLen

數(shù)組長度可以取 length 來得到,但是字符串類型不能取 length,所以我們來實(shí)現(xiàn)一個(gè)求字符串長度的高級(jí)類型。

字符串長度不確定,明顯要用遞歸。每次取一個(gè)并計(jì)數(shù),直到取完,就是字符串長度。

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

類型參數(shù) Str 是待處理的字符串。類型參數(shù) CountArr 是做計(jì)數(shù)的數(shù)組,默認(rèn)值 [] 代表從 0 開始。

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

如果模式匹配不滿足,代表計(jì)數(shù)結(jié)束,返回計(jì)數(shù)數(shù)組的長度 CountArr['length']。

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

GreaterThan

能夠做計(jì)數(shù)了,那也就能做兩個(gè)數(shù)值的比較。

我們往一個(gè)數(shù)組類型中不斷放入元素取長度,如果先到了 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;

類型參數(shù) Num1 和 Num2 是待比較的兩個(gè)數(shù)。

類型參數(shù) CountArr 是計(jì)數(shù)用的,會(huì)不斷累加,默認(rèn)值是 [] 代表從 0 開始。

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

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

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

如果都沒到就往計(jì)數(shù)數(shù)組 CountArr 中放入一個(gè)元素,繼續(xù)遞歸。

這樣就實(shí)現(xiàn)了數(shù)值比較。

當(dāng) 3 和 4 比較時(shí):

當(dāng) 6 和 4 比較時(shí):

Fibonacci談到了數(shù)值運(yùn)算,就不得不提起經(jīng)典的 Fibonacci 數(shù)列的計(jì)算。

Fibonacci

數(shù)列是 1、1、2、3、5、8、13、21、34、…… 這樣的數(shù)列,有當(dāng)前的數(shù)是前兩個(gè)數(shù)的和的規(guī)律。

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

也就是遞歸的加法,在 TypeScript 類型編程里用構(gòu)造數(shù)組來實(shí)現(xiàn)這種加法:

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

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

類型參數(shù) PrevArr 是代表之前的累加值的數(shù)組。類型參數(shù) CurrentArr 時(shí)代表當(dāng)前數(shù)值的數(shù)組。

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

類型參數(shù) Num 代表求數(shù)列的第幾個(gè)數(shù)。

判斷當(dāng)前 index 也就是 IndexArr['length'] 是否到了 Num,到了就返回當(dāng)前的數(shù)值 CurrentArr['length']。

否則求出當(dāng)前 index 對(duì)應(yīng)的數(shù)值,用之前的數(shù)加上當(dāng)前的數(shù) [...PrevArr, ... CurrentArr]。

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

這就是遞歸計(jì)算 Fibinacci 數(shù)列的數(shù)的過程。

可以正確的算出第 8 個(gè)數(shù)是 21:

總結(jié)

TypeScript 類型系統(tǒng)沒有加減乘除運(yùn)算符,所以我們通過數(shù)組類型的構(gòu)造和提取,然后取長度的方式來實(shí)現(xiàn)數(shù)值運(yùn)算。

我們通過構(gòu)造和提取數(shù)組類型實(shí)現(xiàn)了加減乘除,也實(shí)現(xiàn)了各種計(jì)數(shù)邏輯。

用數(shù)組長度做計(jì)數(shù)這一點(diǎn)是 TypeScript 類型體操中最麻煩的一個(gè)點(diǎn),也是最容易讓新手困惑的一個(gè)點(diǎn)。


標(biāo)題名稱:TypeScript類型體操:數(shù)組長度實(shí)現(xiàn)數(shù)值運(yùn)算
文章出自:http://www.dlmjj.cn/article/dpjeicp.html