TypeScript类型怎么实现加减乘除

其他教程   发布日期:2025年02月21日   浏览次数:182

这篇文章主要讲解了“TypeScript类型怎么实现加减乘除”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“TypeScript类型怎么实现加减乘除”吧!

在网上看到这道题目:请用TS类型实现整除?

  1. type A = Divide<1, 0> // never
  2. type B = Divide<4, 2> // 2
  3. type C = Divide<10, 3> // 3

看完题目,我真的毫无思路,TS类型还能实现除法???一脸懵逼的我认真地研究了一位叫做 JoeYan大佬的解答:

  1. type Tuple<T extends number, U extends any[] = []> =
  2. U['length'] extends T ? U : Tuple<T, [...U, any]>
  3. type Subtract<
  4. A extends number,
  5. B extends number
  6. > = Tuple<A> extends [...Tuple<B>, ...infer R] ? R['length'] : never
  7. type SmallerThan<
  8. A extends number,
  9. B extends number,
  10. S extends any[] = []
  11. > = S['length'] extends B
  12. ? false
  13. : S['length'] extends A
  14. ? true
  15. : SmallerThan<A, B, [...S,A]>
  16. type Divide<A extends number, B extends number, S extends any[] = []> =
  17. B extends 0 ? never : SmallerThan<A, B> extends true ? S['length'] : Divide<Subtract<A, B>, B, [...S, any]>;
  18. type res = Divide<200, 10> // 20

分析

乍一看,真的惊呆了,但是一步一步分析,还是能够看懂的,本文将整个研究的过程记录了下来:

TS类型没有直接提供数字的加减乘除,所以这位大佬的减法和整除都是通过数组长度计数来实现的。我平时体操练习很少,在没看他的解答前,我永远不会想到还能这么玩儿。

Divide

如果要实现98%10,假设A是98,B是10,让A一直减B,直到A小于B,无法继续再减,就能得到整除的结果。

A能减去9次B,每次进行减10的时候,往S(用来计数的数组,初始值为空数组)里面push一个元素。A减去9次10后,S数组的长度是9。此时A是8,B是10,A小于B,返回S的长度9。

  1. type Divide<A extends number, B extends number, S extends number[] = []> =
  2. B extends 0 ? never : SmallerThan<A, B> extends true ? S['length'] : Divide<Subtract<A, B>, B, [...S, any]>;

上面这段代码的字面意思是:

  • B是否为0,直接返回never

  • A如果小于B,返回S的长度

  • A如果大于B,我们执行A-B,然后我们给S数组push一个元素,再次计算Divide

接下来,让我们开始逐个分析。

SmallerThan

SmallerThan用于判断A是否小于B

  1. type res = SmallerThan<10,2> // res为false
  2. type res = SmallerThan<2,20> // res为true
  1. type SmallerThan<
  2. A extends number,
  3. B extends number,
  4. S extends any[] = []
  5. > = S['length'] extends B
  6. ? false
  7. : S['length'] extends A
  8. ? true
  9. : SmallerThan<A, B, [...S,any]>

字面上看起来是:

  • S的长度等于B,返回false

  • S的长度不等于B且S的长度等于A,返回true

  • S的长度不等于A和B,将any推入S数组

接下来举例来看:

  1. type res = SmallerThan<3,2>
  2. // 首先S['length']=0 ,所以不等于A和B,此时将any推入数组,S数组变成[any]
  3. // 接下来S['length'] =1,还是B等于A和B,此时继续将A放入数组,S数组变成[any,any]
  4. // 此时S['length'] = 2,所以得出S的长度等于B,返回false

总之,S的长度是一次一次的累加的,先等于谁的长度,谁就更小。 如果S的长度先等于B的长度,那么就是

  1. A>B
。如果S的长度先等于A的长度,就是
  1. A<B

Tuple

作用是将数字转成数组,且数组的长度等于数字的大小

  1. type Tuple<T extends number, U extends any[] = []> =
  2. U['length'] extends T ? U : Tuple<T, [...U, any]>
  3. type res4 = Tuple<3> // [any, any, any]‘
  4. // 基本上和上面的SmallerThan差不多,就是不够长度,就push一个any进去

Subtract

顾名思义,获取A-B的值

  1. type Subtract<
  2. A extends number,
  3. B extends number
  4. > = Tuple<A> extends [...Tuple<B>, ...infer R] ? R : never
  5. type res3 = Subtract<10,8> // [any, any]
  6. type Subtract<
  7. A extends number,
  8. B extends number
  9. > = Tuple<A> extends [...Tuple<B>, ...infer R] ? R['length'] : never
  10. type res3 = Subtract<20,10> // 10
  11. // 一开始把A转换长度为20的数组,B转换成长度为10的数组,然后让ts自己去infer,A的长度等于B的长度加上多少长度的数组,然后返回R的长度

最后

前面已经实现了整除和减法,本着练习的态度,让我们再实现一下乘法和加法。

加法

仿照前面的Subtract,不难实现:

  1. type Add<A extends number, B extends number > = [...Tuple<A>,...Tuple<B>] extends [... infer T] ? T['length']:never

乘法

接下来,让我们实现一下乘法:

  1. 5*6
可以看作,5+5+5+5+5+5。

  1. A*B
,也就是A要累加自己B次。如果我们每进行一次加法,就让被乘数B减一,直到被乘数B为0,也就完成了累加。
  1. type Tuple<T extends number, U extends any[] = []> =
  2. U['length'] extends T ? U : Tuple<T, [...U, any]>
  3. type Mutiply<A extends number, B extends number, S extends any[] = []> = B extends 0 ? S['length'] : Mutiply<A, Subtract<B, 1>, [...S, ...Tuple<A>]>
  4. type res = Mutiply<5,6> //30

坑点

  1. type Tuple<T extends number, S extends any[] = []> = S['length'] extends T ? S : Tuple<T, [...S, any]> // 不报错
  2. // type Tuple<T extends number, S extends any[] = []> = T extends S['length'] ? S : Tuple<T, [...S, any]>
  3. // 不能写成T extends S['length'],ts会报递归可能是无限的

以上就是TypeScript类型怎么实现加减乘除的详细内容,更多关于TypeScript类型怎么实现加减乘除的资料请关注九品源码其它相关文章!