类型体操基本功-简单四则运算
很多类型推导的场景下需要涉及到数字的计算,这篇文章就介绍下常规四则运算的实现思路。
加法
实现
首先应该想到,在Typescript中得到一个数字结果的方法最简单的就是获取数组的长度。
type Length<T extends any[]> = T["length"]
加法沿着这个思路就很好解决:将两个数字转化为对应长度的数组,再合并计算长度即可。
// 数字转数组
type ConstructTuple<L extends number, Res extends unknown[] = []> = Res['length'] extends L
? Res
: ConstructTuple<L, [...Res, unknown]>
// 合并计算长度
type Add<A extends number, B extends number> = [...ConstructTuple<A>, ...ConstructTuple<B>]['length']
至此我们就实现了Add基础泛型。结合一个实例看一下使用。
应用
实现一个获取两个数字之间范围的泛型。
type result = NumberRange<2 , 9> // | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
已知左右边界,设置一个当前值和结果值,从左边界开始递归加1,到达右边界返回结果值即可。
type NumberRange<L extends number, R extends number, Cur extends number = L, Res = L | R> = Cur extends R
? Res
: NumberRange<L, R, Add<Cur, 1>, Res | Cur>
许多工具泛型的实现都离不开四则运算的基础泛型。接下来看下减法基础泛型的实现。
减法
减法的实现不能像加法一样做简单的合并,不过思路差别也不大,都是利用数组长度去计算。同样将两个数字转成数组,每次移除更长数组的一个元素,并将结果加1,当两个数组长度相等时,记录的结果就是减法结果。
在此之前先实现数组的推出操作。
type Shift<T extends any[]> = T extends [infer A, ...infer B] ? B : []
再基于减法思路实现数组的减法计算。
type SubList<A extends unknown[], B extends unknown[], Res extends unknown[] = []> = A['length'] extends B['length']
? Res['length']
: SubList<Shift<A>, B, [...Res, unknown]>
最后封装一层数字转数组就完成了。
type Sub<A extends number, B extends number> = SubList<ConstructTuple<A>, ConstructTuple<B>>
还有一种更简单的方法,利用Typescript的数组解构和infer特性直接推断长度。
type Sub2<A extends number, B extends number> = ConstructTuple<A> extends [...ConstructTuple<B>, ...infer Res]
? Res['length']
: never
乘法
乘法本质上是加法的累加,比如2 * 3即可等效于2 + 2 + 2。基于加法实现,添加一个计数器,以左侧数字为加法基础,右侧数字为计数器即可。
type Muti<A extends number, B extends number, Res extends unknown[] = []> = B extends 0
? Res['length']
: Muti<A, Sub<B, 1>, [...Res, ...ConstructTuple<A>]>
除法
除法同乘法, 3 / 2等效于 3 - 2 - 2.....的循环,直到剩余数小于除数为止。
type Div<A extends number, B extends number, Res extends unknown[] = []>
= Sub<A, B> extends never
? Res['length']
: Div<Sub<A, B>, B, [...Res, unknown]>
小结
当然以上实现的四则运算还有很多缺陷,比如
- 不支持负数和小数
- 对运算顺序有要求
- 除法是向上取整的
不过在大多数更高阶的类型设计中,并不会真正进行单纯复杂的以计算结果为目的的四则运算,更多的是作为记数器的逻辑需要去进行基础计算,所以简单四则也基本能覆盖需求场景。如果对更复杂的四则感兴趣,也可以思考下如何实现。
-- EOF --
添加在分类「
前端开发
」下,并被添加
「TypeScript」
标签。