【Typescript 系列】类型体操之中等篇题型(第二十三节)解读

42 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情

1. 引言

接着上一节中,接下来我们继续Ts中等篇的题型练习 https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md 提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!

2. 题型

  1. Trunc:实现Math的类型版本。Trunc,它接受字符串或数字,并通过删除小数部分返回数字的整数部分。
type A = Trunc<12.34> // 12

思路:    该题利用infer 关键字即可拆分字符串中“。”小数点前的整数部分;但是请注意,如果是当检测对象为数字类型的时候,infer 关键字就不行了,这时候我们要使用字面量转换把数字类型先一步转化为字符串类型在做判断;完成。 解答:

type Trunc<S extends string | number> = `${S}` extends `${infer M}.${infer N}` ? M : `${S}`
type Demo = Trunc<0.1> // type Demo = "0"
type Demo2 = Trunc<1.234> // type Demo2 = "1"
type Demo3 = Trunc<12.345> // type Demo3 = "12"
type Demo4 = Trunc<-5.1> // type Demo4 = "-5"
type Demo5 = Trunc<'1.234'> // type Demo5 = "1"
type Demo6 = Trunc<'-10.234'> // type Demo6 = "-10"
type Demo7 = Trunc<10> // type Demo7 = "10"

  1. IndexOf:实现Array的类型版本。indexOf indexOf< T,标签;取数组T中的任意U,返回数组T中第一个U的下标。
type Res = IndexOf<[1, 2, 3], 2>; // expected to be 1
type Res1 = IndexOf<[2,6, 3,8,4,1,7, 3,9], 3>; // expected to be 2
type Res2 = IndexOf<[0, 0, 0], 2>; // expected to be -1

思路:    首先自定义一个数组负责记录对应数组目标对应值的对应位置。然后开始使用infer 关键字解构数组内容的每一个属性值,使用Equal 作为对比比较,当相等时说明找到对应目标值,这时候记录数组 indexArr 的长度就是下标值,这时候可以在加一个判空处理;如果不等于目标值说明还没找到,这时候递归处理并且让indexArr 自增随意值。完成。 解答:

type IndexOf<T extends any[], U extends number | any, indexArr extends any[] = []> = T extends [infer M, ...infer N] ? 
  Equal<M, U> extends true  ? 
  indexArr['length'] extends 0 ? 
  -1 : indexArr['length'] 
   : IndexOf<N, U, [...indexArr, 0]> 
: -1
type Demo = IndexOf<[1, 2, 3], 2> // type Demo = 1
type Demo2 = IndexOf<[2, 6, 3, 8, 4, 1, 7, 3, 9], 3> // type Demo2 = 2
type Demo3 = IndexOf<[0, 0, 0], 2> // type Demo3 = -1
type Demo4 = IndexOf<[string, 1, number, 'a'], number> // type Demo4 = 2
type Demo5 = IndexOf<[string, 1, number, 'a', any], any> // type Demo5 = 4

  1. Join: 实现Array的类型版本。加入<T,U>标签;获取数组T,字符串或数字U,并返回与U缝合的数组T。
type Res = Join<["a", "p", "p", "l", "e"], "-">; // expected to be 'a-p-p-l-e'
type Res1 = Join<["Hello", "World"], " ">; // expected to be 'Hello World'
type Res2 = Join<["2", "2", "2"], 1>; // expected to be '21212'
type Res3 = Join<["o"], "u">; // expected to be 'o'

Expect<Equal<Join<['a', 'p', 'p', 'l', 'e'], '-'>, 'a-p-p-l-e'>>,
  Expect<Equal<Join<['Hello', 'World'], ' '>, 'Hello World'>>,
  Expect<Equal<Join<['2', '2', '2'], 1>, '21212'>>,
  Expect<Equal<Join<['o'], 'u'>, 'o'>>,

思路:    该题考查我们的是解构合并,加上递归的使用;首先我们先解构目标对象的第一个数组值,判断解构第一个属性值后的数组是否就为空数组,如果是则直接返回对应数组,如果不是则拼接拿出来的数组元素值后在拼接上目标拼接字符串,然后递归操作直至结束为止;完成。 解答:

// 答案
type Join<T extends string[], U extends string | number> = 
  T extends [infer L extends string, ...infer R extends string[]]
    ? R['length'] extends 0
      ?  L
      : `${L}${U}${Join<R, U>}`
    : ''