// 15 实现一个通用Last<T>,它接受一个数组T并返回其最后一个元素的类型。 typeLast<T extendsany[]> = T extends [...infer B, infer P] ? P : never;
type arr1 = ['a', 'b', 'c'] type arr2 = [3, 2, 1]
type tail1 = Last<arr1> // expected to be 'c' type tail2 = Last<arr2> // expected to be 1
// 实现 Replace<S, From, To> 将字符串 S 中的第一个子字符串 From 替换为 To 。 typeReplace<S extendsstring, Fromextendsstring, Toextendsstring> = Fromextends'' ? S : S extends (`${infer L}${From}${infer R}`) ? `${L}${To}${R}`: S
type replaced = Replace<'types are fun!', 'fun', 'awesome'> // 期望是 'types are awesome!'
typePromiseParseAll<T extendsany[]> = T extends [infer P, ...infer O] ? P extendsPromise<infer R> ? [R, ...PromiseParseAll<O>] : [P, ...PromiseParseAll<O>] : [] typePromiseAll<T extendsany[]> = Promise<PromiseParseAll<T>> // expected to be `Promise<[number, 42, string]>` typePRes = PromiseAll<[Promise<number>, 42, Promise<string>]>;
字符串
字符串类似
1 2 3 4
typeTrimLeft<T extendsstring> = T extends`${infer L}${infer R}` ? L extends" "|"\n"|"\t" ? TrimLeft<R> : T : never type trimed = TrimLeft<' Hello World '> // 应推导出 'Hello World '
联合类型变交叉类型
利用函数入参的逆变特性,把输入类型构建成函数参数
1 2 3 4 5 6 7 8 9
typeUnionToIntersection<U> = (U extendsany ? (arg: U) =>any : never ) extends ((arg: infer I) =>any) ? I : never typeTestUnion2Intersection = UnionToIntersection<{a: 1} | {b: 2} | {c: 3}> // expected to be {a: 1} & {b: 2} & {c: 3}
判断两个类型相等
大多数非严格情况下的相等使用 A extends B 基本可以做到,譬如前一步的类型中间方法根据条件返回了true或false,接下来要判断结果是否是true,直接用 T extends true ? xxx : xxx 进行接下来的操作就好。
但是枚举类型下,extends无法很好的区分是否可选,是否只读的区别。
1 2 3 4
type a = {a: string} extends {readonlya: string} ? true : false; // true type b = {readonlya: string} extends {a: string} ? true : false; // true type c = {a: string} extends {a?: string} ? true : false; // true type d = {a?: string} extends {a: string} ? true : false; // false
所以严格的相等要借助函数的协变,具体的逻辑我也没get到。。。
1 2 3
exporttypeEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false