Typescript 支持泛型,也叫类型参数,可以对类型参数做一系列运算之后返回新的类型,这就是类型编程
。
因为类型编程实现一些逻辑还是有难度的,所以被戏称为类型体操
。
社区有用 Typescript 类型实现 Lisp 解释器、实现象棋等案例的(知乎可以搜到),这足够说明了 Typescript 类型可以实现各种复杂逻辑。
那 Typescript 类型体操这么难,有没有什么快速掌握的方式呢?
确实有,我总结了一些套路,可以快速提升 ts 类型体操水平。比如今天要讲的套路--模式匹配。
Typescript 类型的模式匹配
我们知道,字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。
Typescript 的类型也同样可以做模式匹配。
比如,提取 Promise<T> 的值的类型:
我们通过 extends 对传入的类型参数 T 做模式匹配,其中 value 部分是需要提取的,通过 infer 类声明一个局部变量 R 来保存,如果匹配,就返回匹配到的 R,否则就返回 never 代表没匹配到。
这就是 Typescript 类型的模式匹配。
小结一下: Typescript 类型的模式匹配是通过 extends 对类型参数做匹配,结果保存到通过 infer 声明的局部类型变量里,如果匹配就能从该局部变量里拿到提取出的类型。
这个模式匹配的套路有多有用呢?我们来看下在数组、字符串、函数等类型里的应用。
数组类型的模式匹配
pop
pop 是去掉最后一个元素,可以通过模式匹配来实现:
我们通过模式匹配取出最后一个元素的类型和前面的元素的类型,分别用 infer 放入不同的变量里,然后构造一个新的数组类型返回。
shift
同样,shift 是去掉最开始的元素,也是类似的匹配方式来实现:
字符串类型的模式匹配
trim
trim 是去掉前后的空格、制表符、换行符,那么就通过模式匹配取出后面的字符,通过 infer 放入新的变量返回就行。
先实现 TrimLeft:
如果匹配就继续递归 TrimLeft,直到前面没有空白字符。
再实现 TrimRight:
然后两者结合,就是 Trim:
replace
replace 是替换字符串中的一部分,可以通过模式匹配取出这段字符串前后的子串,通过 infer 放入不同的变量,然后和替换后的部分组成新字符串。
函数类型的模式匹配
参数类型
取出参数的类型是通过模式匹配拿到参数部分,放入 infer 声明的变量里返回。
返回值类型
取出返回值类型也是通过模式匹配拿到返回值部分,放入 infer 声明的类型变量里返回。
总结
类型编程是对类型参数(泛型)做一系列运算之后返回新的类型,也叫类型体操。
类型体操可以实现很多复杂的逻辑,学习起来也有一定的难度,但是掌握一些套路之后也能快速掌握。
这些套路里面最常用的就是模式匹配了,类似字符串匹配和提取子串,类型也可以通过 extends 对类型参数做匹配,把需要提取的部分保存到通过 infer 声明的局部类型变量里。
类型参数的模式匹配的套路在字符串类型、数组类型、函数类型等都有大量的应用,掌握这一个套路可以提升一大截类型体操的水平。