TypeScript類型實(shí)現(xiàn)加減乘除詳解
引言
在網(wǎng)上看到這道題目:請(qǐng)用TS類型實(shí)現(xiàn)整除?
type A = Divide<1, 0> // never type B = Divide<4, 2> // 2 type C = Divide<10, 3> // 3
看完題目,我真的毫無思路,TS類型還能實(shí)現(xiàn)除法???一臉懵逼的我認(rèn)真地研究了一位叫做 JoeYan大佬的解答:
type Tuple<T extends number, U extends any[] = []> =
U['length'] extends T ? U : Tuple<T, [...U, any]>
type Subtract<
A extends number,
B extends number
> = Tuple<A> extends [...Tuple<B>, ...infer R] ? R['length'] : never
type SmallerThan<
A extends number,
B extends number,
S extends any[] = []
> = S['length'] extends B
? false
: S['length'] extends A
? true
: SmallerThan<A, B, [...S,A]>
type Divide<A extends number, B extends number, S extends any[] = []> =
B extends 0 ? never : SmallerThan<A, B> extends true ? S['length'] : Divide<Subtract<A, B>, B, [...S, any]>;
type res = Divide<200, 10> // 20
分析
乍一看,真的驚呆了,但是一步一步分析,還是能夠看懂的,本文將整個(gè)研究的過程記錄了下來:
TS類型沒有直接提供數(shù)字的加減乘除,所以這位大佬的減法和整除都是通過數(shù)組長(zhǎng)度計(jì)數(shù)來實(shí)現(xiàn)的。我平時(shí)體操練習(xí)很少,在沒看他的解答前,我永遠(yuǎn)不會(huì)想到還能這么玩兒。
Divide
如果要實(shí)現(xiàn)98%10,假設(shè)A是98,B是10,讓A一直減B,直到A小于B,無法繼續(xù)再減,就能得到整除的結(jié)果。
A能減去9次B,每次進(jìn)行減10的時(shí)候,往S(用來計(jì)數(shù)的數(shù)組,初始值為空數(shù)組)里面push一個(gè)元素。A減去9次10后,S數(shù)組的長(zhǎng)度是9。此時(shí)A是8,B是10,A小于B,返回S的長(zhǎng)度9。
type Divide<A extends number, B extends number, S extends number[] = []> =
B extends 0 ? never : SmallerThan<A, B> extends true ? S['length'] : Divide<Subtract<A, B>, B, [...S, any]>;
上面這段代碼的字面意思是:
- B是否為0,直接返回never
- A如果小于B,返回S的長(zhǎng)度
- A如果大于B,我們執(zhí)行A-B,然后我們給S數(shù)組push一個(gè)元素,再次計(jì)算Divide
接下來,讓我們開始逐個(gè)分析。
SmallerThan
SmallerThan用于判斷A是否小于B
type res = SmallerThan<10,2> // res為false type res = SmallerThan<2,20> // res為true
type SmallerThan<
A extends number,
B extends number,
S extends any[] = []
> = S['length'] extends B
? false
: S['length'] extends A
? true
: SmallerThan<A, B, [...S,any]>
字面上看起來是:
- S的長(zhǎng)度等于B,返回false
- S的長(zhǎng)度不等于B且S的長(zhǎng)度等于A,返回true
- S的長(zhǎng)度不等于A和B,將any推入S數(shù)組
接下來舉例來看:
type res = SmallerThan<3,2> // 首先S['length']=0 ,所以不等于A和B,此時(shí)將any推入數(shù)組,S數(shù)組變成[any] // 接下來S['length'] =1,還是B等于A和B,此時(shí)繼續(xù)將A放入數(shù)組,S數(shù)組變成[any,any] // 此時(shí)S['length'] = 2,所以得出S的長(zhǎng)度等于B,返回false
總之,S的長(zhǎng)度是一次一次的累加的,先等于誰(shuí)的長(zhǎng)度,誰(shuí)就更小。 如果S的長(zhǎng)度先等于B的長(zhǎng)度,那么就是A>B。如果S的長(zhǎng)度先等于A的長(zhǎng)度,就是A<B。
Tuple
作用是將數(shù)字轉(zhuǎn)成數(shù)組,且數(shù)組的長(zhǎng)度等于數(shù)字的大小
type Tuple<T extends number, U extends any[] = []> =
U['length'] extends T ? U : Tuple<T, [...U, any]>
type res4 = Tuple<3> // [any, any, any]‘
// 基本上和上面的SmallerThan差不多,就是不夠長(zhǎng)度,就push一個(gè)any進(jìn)去
Subtract
顧名思義,獲取A-B的值
type Subtract<
A extends number,
B extends number
> = Tuple<A> extends [...Tuple<B>, ...infer R] ? R : never
type res3 = Subtract<10,8> // [any, any]
type Subtract<
A extends number,
B extends number
> = Tuple<A> extends [...Tuple<B>, ...infer R] ? R['length'] : never
type res3 = Subtract<20,10> // 10
// 一開始把A轉(zhuǎn)換長(zhǎng)度為20的數(shù)組,B轉(zhuǎn)換成長(zhǎng)度為10的數(shù)組,然后讓ts自己去infer,A的長(zhǎng)度等于B的長(zhǎng)度加上多少長(zhǎng)度的數(shù)組,然后返回R的長(zhǎng)度
最后
前面已經(jīng)實(shí)現(xiàn)了整除和減法,本著練習(xí)的態(tài)度,讓我們?cè)賹?shí)現(xiàn)一下乘法和加法。
加法
仿照前面的Subtract,不難實(shí)現(xiàn):
type Add<A extends number, B extends number > = [...Tuple<A>,...Tuple<B>] extends [... infer T] ? T['length']:never
乘法
接下來,讓我們實(shí)現(xiàn)一下乘法:
5*6 可以看作,5+5+5+5+5+5。
A*B,也就是A要累加自己B次。如果我們每進(jìn)行一次加法,就讓被乘數(shù)B減一,直到被乘數(shù)B為0,也就完成了累加。
type Tuple<T extends number, U extends any[] = []> =
U['length'] extends T ? U : Tuple<T, [...U, any]>
type Mutiply<A extends number, B extends number, S extends any[] = []> = B extends 0 ? S['length'] : Mutiply<A, Subtract<B, 1>, [...S, ...Tuple<A>]>
type res = Mutiply<5,6> //30
坑點(diǎn)
type Tuple<T extends number, S extends any[] = []> = S['length'] extends T ? S : Tuple<T, [...S, any]> // 不報(bào)錯(cuò) // type Tuple<T extends number, S extends any[] = []> = T extends S['length'] ? S : Tuple<T, [...S, any]> // 不能寫成T extends S['length'],ts會(huì)報(bào)遞歸可能是無限的
總結(jié)
我覺得還是套路為主,在研究了別人的除法實(shí)現(xiàn)后,也就能很容易實(shí)現(xiàn)加法和乘法。但如果沒有前面的研究,想破腦子也很難實(shí)現(xiàn)。
以上就是TypeScript類型實(shí)現(xiàn)加減乘除詳解的詳細(xì)內(nèi)容,更多關(guān)于TypeScript類型加減乘除的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
rollup?cli開發(fā)全面系統(tǒng)性rollup源碼分析
這篇文章主要為大家介紹了rollup?cli開發(fā)全網(wǎng)系統(tǒng)性rollup源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
TypeScript?5.0?正式發(fā)布及使用指南詳解
這篇文章主要為大家介紹了TypeScript?5.0?正式發(fā)布及使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
自動(dòng)生成typescript類型聲明工具實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了自動(dòng)生成typescript類型聲明工具實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
聯(lián)合類型Union?Types與交叉類型Intersection?Types區(qū)別解析
這篇文章主要為大家介紹了聯(lián)合類型Union?Types與交叉類型Intersection?Types區(qū)別詳解2023-06-06
FastAdmin表單驗(yàn)證data-rule插件—Nice-validator的使用方法
FastAdmin的表單驗(yàn)證data-rule非常方便,也很炫酷,采用的Nice-validator是一款非常強(qiáng)大的表單驗(yàn)證插件,通過簡(jiǎn)單在元素上配置規(guī)則,即可達(dá)到驗(yàn)證的效果,怎么使用Nice-validator插件呢2023-09-09
TypeScript類型實(shí)現(xiàn)加減乘除詳解
這篇文章主要為大家介紹了TypeScript類型實(shí)現(xiàn)加減乘除示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04

