TypeScript 模式匹配
最近尝试学习了下 TypeScript 的高级应用,正好接触到了模式匹配,写一篇文章来记录下所学内容。
介绍
在 TypeScript 中 extends、infer 关键字是相当重要的,extends 除了可以约束类型以外,还可以进行模式匹配,然后通过 infer 声明变量来进行值的存储,例如下方定义的 Promise 类型:
type Result = Promise<'suemor'>;
我们要实现一个类型,把 suemor
提取出来,使 Result 的值为 suemor
,我们可以这样写:
type GetResult<T> = T extends Promise<infer Value> ? Value : never;
函数
我们在函数中同样可以进行类型匹配,提取它的参数,返回值类型。例如下方提取函数的参数类型:
type GetResult<T extends Function> = T extends (...args:infer Args) => unknown ? Args : never
type Result = GetResult<(name: string, age: number) => string>;
通过 infer 将参数类型保存到变量 Args 里面。
数组类型
数组也同样适用类型匹配,例如我们想提取它第一个元素的类型:
type Result = GetResult<[1, 2, 3]>;
type GetResult<T extends unknown[]> = T extends [infer First, ...unknown[]]
? First
: never;
利用 infer 获取第一个元素的类型,剩余的元素类型用存放在 ...unknown[]
中。
字符串类型
字符串类型也可以进行模式匹配,把匹配的字符串,存放在 infer 的局部变量中,如下实现字符串替换:
type Result = GetResult<"suemor and mike", "suemor", "jack">;
type GetResult<
Str extends string,
From extends string,
To extends string
> = Str extends `${infer Prefix}${From}${infer Suffix}`
? `${Prefix}${To}${Suffix}`
: Str;
把要替换的值(From)前后的字符串都存放在 Prefix 和 Suffix 两个变量中,再把 From 换成目标值(To)即可。
还有个例子,判断字符串是否以某个前缀开头:
type Result = GetResult<"suemor and mike", "suemor">;
type GetResult<
Str extends string,
Prefix extends string
> = Str extends `${Prefix}${string}` ? true : false;
把 Prefix 放在字符串开头进行匹配即可。