目录
什么是条件提取?
说明:通过extends 对类型进行匹配,将匹配成功的结果保存到infer类型变量中,最后提取这个类型
其实就是我们之前提到的 extends ? 语法
本节 我们来讲述 Ts类型体操 使用 extends ? 配合 infer 做条件提取,我会通过代码示例 去讲解数组、字符串、函数、构造器、索引等类型如何去使用条件提取
1、数组类型
(1)提取数组中的第一个元素
type Arr = [1, 2, 3, 4, 5, 6];
type getArrFirst<T> = T extends unknown[]
? T extends [infer First, ...unknown[]]
? First
: unknown
: never;
type res2 = getArrFirst<Arr>;
说明:
首先我们定义了一个 Arr 的 类型别名,表示一个包含六个数字(1 到 6)的元组。
然后我们定义了一个类型工具,getArrFirst<T>
它首先检查传入的类型 T 是否是数组,如果 T 不是数组,getArrFirst<T> 的结果就是 never。
如果 T 是数组,它会进一步检查 T 是否有一个明确的第一个元素和后续的元素。这是通过
[ infer First, ...unknown [ ] ] 实现的,
其中 infer First 尝试将数组的第一个元素类型分配给新的类型变量 First,而 ...unknown[] 匹配数组的其余部分。
如果这个条件满足(即 T 确实有一个明确的第一个元素),那么 getArrFirst<T> 的结果就是 First。
如果不满足(例如,T 是一个空数组 []),则结果是 unknown。
(2)提取数组中最后一个元素
type getArrLast<T extends unknown[]> = T extends [...unknown[], infer Last]
? Last
: never;
(3)提取数组中间部分的元素
type RemoveTheFirstAndTheLastArr<T extends unknown[]> = T extends [
unknown,
...infer res,
unknown
]
? res
: never;
type r3 = RemoveTheFirstAndTheLastArr<Arr>;
这几段代码都是相似的,只是提取部分的逻辑有些许差别,我们也可以根据上面去实现
比如 :提取除了第一个元素,返回剩余的部分
2、字符串类型
(1)是否以某个前缀开头
type StartsWith<
Prefix extends string,
str extends string
> = str extends `${Prefix}${string}` ? true : false;
type c = "#";
type d = "#vvv";
type e = "vvv";
type resd = StartsWith<c, d>;
type resc = StartsWith<c, e>;
说明:这段代码中我们 首先去 约束 Prefix 和 str 都应该是string类型,
然后我们通过条件提取 去判断 str 是否以Prefix为前缀 如果正确则返回 true 否则返回 false
(2)提取传入的类型,并返回新的类型
type str = "abcde";
type InterceptString<
str extends string,
form extends string,
to extends string
> = str extends `${infer before}${form}${infer after}`
? `${before}${to}${after}`
: str;
type resi = InterceptString<str, "c", "-to-">;
说明:在这段代码中,我们传入了3个泛型 并 约束为 string 类型,
然后使用条件提取,首先判断 str 是否 可以通过 from 去拆分成 前 中 后 三个部分 如果可以的话 我们返回新的类型 前+to+后,否则返回str
(3)去除首尾空白符
type str1 = " a";
type str2 = "a ";
type str3 = " a ";
// 去除首部空格
type RemoveSpacePrelude<T extends string> = T extends `${
| " "
| "\n"
| "\t"}${infer str}`
? RemoveSpacePrelude<str>
: T;
type res1 = RemoveSpacePrelude<str1>;
// 去除尾部空格
type RemoveSpaceRump<T extends string> = T extends `${infer str}${
| " "
| "\n"
| "\t"}`
? RemoveSpaceRump<str>
: T;
type resr = RemoveSpaceRump<str2>;
// 去除前后空格
type res4 = RemoveSpacePrelude<RemoveSpaceRump<str3>>;
说明:我们将这个功能拆分为两个类型工具, 方便大家理解
这里简单说下去除首部空格的逻辑:
首先我们先定义了一个去除首部空格的工具RemoveSpacePrelude,他接受一个泛型<T>约束为字符串作为参数,
然后我们使用条件提取 去判断 T 前面是否有空格,如果有的话,我们会去掉前面的空格并将满足条件的通过infer命名为str,然后会进入递归,传入删除空格的新参数str,直到首部没有空格返回 处理好的T
尾部和首部逻辑几乎是一致的。