类型体操刷题系列(八)—Trim/Capitalize/Replace

218 阅读2分钟

目的

Github上的类型体操,让你写出更加优雅的TS类型定义,以及探寻TS中我们不熟悉的只是,让我们开始TS的类型挑战把~2022希望通过更文的方式来督促自己学习,每日三题,坚持日更不断~~

ts 类型体操 github 我的解答

题目大纲

  1. Medium Trim
  2. Medium Capitalize
  3. Medium Replace

01. Medium Trim

题目要求

import { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Trim<'str'>, 'str'>>,
  Expect<Equal<Trim<' str'>, 'str'>>,
  Expect<Equal<Trim<'     str'>, 'str'>>,
  Expect<Equal<Trim<'str   '>, 'str'>>,
  Expect<Equal<Trim<'     str     '>, 'str'>>,
  Expect<Equal<Trim<'   \n\t foo bar \t'>, 'foo bar'>>,
]

我的答案

type EmptyType = " " | "\t" | "\n";

type TL<S extends string> = S extends `${infer P}${infer K}`
  ? P extends " " | "\t" | "\n"
    ? TL<K>
    : S
  : never;

type TR<S extends string> = S extends `${infer P}${EmptyType}` ? TR<P> : S;

type Trim<S extends string> = TR<TL<S>>;

知识点

  1. trimRight 不能和 TL 写的一样, 因为这里的 P 和 K其实是贪婪的抓取,不会想象成从末尾开始取,所以这里要明确 extends 是不是末尾有 EmptyType
  2. 对某个想要 TS 识别的特殊结构,直接枚举出来就行

2. Medium Capitalize

题目要求

import { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Capitalize1<'foobar'>, 'Foobar'>>,
  Expect<Equal<Capitalize1<'FOOBAR'>, 'FOOBAR'>>,
  Expect<Equal<Capitalize1<'foo bar'>, 'Foo bar'>>,
  Expect<Equal<Capitalize1<''>, ''>>,
  Expect<Equal<Capitalize1<'a'>, 'A'>>,
  Expect<Equal<Capitalize1<'b'>, 'B'>>,
  Expect<Equal<Capitalize1<'c'>, 'C'>>,
  Expect<Equal<Capitalize1<'d'>, 'D'>>,
  Expect<Equal<Capitalize1<'e'>, 'E'>>,
  Expect<Equal<Capitalize1<'f'>, 'F'>>,
  Expect<Equal<Capitalize1<'g'>, 'G'>>,
  Expect<Equal<Capitalize1<'h'>, 'H'>>,
  Expect<Equal<Capitalize1<'i'>, 'I'>>,
  Expect<Equal<Capitalize1<'j'>, 'J'>>,
  Expect<Equal<Capitalize1<'k'>, 'K'>>,
  Expect<Equal<Capitalize1<'l'>, 'L'>>,
  Expect<Equal<Capitalize1<'m'>, 'M'>>,
  Expect<Equal<Capitalize1<'n'>, 'N'>>,
  Expect<Equal<Capitalize1<'o'>, 'O'>>,
  Expect<Equal<Capitalize1<'p'>, 'P'>>,
  Expect<Equal<Capitalize1<'q'>, 'Q'>>,
  Expect<Equal<Capitalize1<'r'>, 'R'>>,
  Expect<Equal<Capitalize1<'s'>, 'S'>>,
  Expect<Equal<Capitalize1<'t'>, 'T'>>,
  Expect<Equal<Capitalize1<'u'>, 'U'>>,
  Expect<Equal<Capitalize1<'v'>, 'V'>>,
  Expect<Equal<Capitalize1<'w'>, 'W'>>,
  Expect<Equal<Capitalize1<'x'>, 'X'>>,
  Expect<Equal<Capitalize1<'y'>, 'Y'>>,
  Expect<Equal<Capitalize1<'z'>, 'Z'>>,
]

我的解答

type CapMap = {
  a: "A";
  b: "B";
  c: "C";
  d: "D";
  e: "E";
  f: "F";
  g: "G";
  h: "H";
  i: "I";
  j: "J";
  k: "K";
  l: "L";
  m: "M";
  n: "N";
  o: "O";
  p: "P";
  q: "Q";
  r: "R";
  s: "S";
  t: "T";
  u: "U";
  v: "V";
  w: "W";
  x: "X";
  y: "Y";
  z: "Z";
};

type Capitalize1<S extends string> = S extends ""
  ? ""
  : S extends `${infer P}${infer T}`
  ? P extends keyof CapMap
    ? `${CapMap[P]}${T}`
    : S
  : never;

知识点

  1. 字符串模版的推断
  2. keyof 的使用

3. Medium Replace

题目要求

import { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Replace<'foobar', 'bar', 'foo'>, 'foofoo'>>,
  Expect<Equal<Replace<'foobarbar', 'bar', 'foo'>, 'foofoobar'>>,
  Expect<Equal<Replace<'foobarbar', '', 'foo'>, 'foobarbar'>>,
  Expect<Equal<Replace<'foobarbar', 'bra', 'foo'>, 'foobarbar'>>,
  Expect<Equal<Replace<'', '', ''>, ''>>,
]

我的解答

type Replace<
  S extends string,
  From extends string,
  To extends string
> = From extends ""
  ? S
  : S extends `${infer T}${From}${infer Z}`
  ? `${T}${To}${Z}`
  : S;

知识点

  1. 字符串推断的类型可以是动态外部传入的
  2. 替换的时候,对应替换的值,也可以是直接通过字符串拼接的方式进行组合的