类型体操刷题系列(十五)— DropChar/MinusOne/PickByType

387 阅读2分钟

目的

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

ts 类型体操 github 我的解答

题目大纲

  1. Medium drop char
  2. Medium minus one
  3. Medium pick by type

01. Medium Drop Char

题目要求

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

type cases = [
  Expect<Equal<DropChar<'butter fly!', ''>, 'butterfly!'>>,
  Expect<Equal<DropChar<'butter fly!', ' '>, 'butterfly!'>>,
  Expect<Equal<DropChar<'butter fly!', '!'>, 'butter fly'>>,
  Expect<Equal<DropChar<'    butter fly!        ', ' '>, 'butterfly!'>>,
  Expect<Equal<DropChar<' b u t t e r f l y ! ', ' '>, 'butterfly!'>>,
  Expect<Equal<DropChar<' b u t t e r f l y ! ', 'b'>, '  u t t e r f l y ! '>>,
  Expect<Equal<DropChar<' b u t t e r f l y ! ', 't'>, ' b u   e r f l y ! '>>,
]

我的答案

type DropChar<
  S,
  C extends string,
  R extends string = ""
> = S extends `${infer P}${infer K}`
  ? C extends ""
    ? `${R}${DropChar<S, " ", R>}`
    : P extends C
    ? `${R}${DropChar<K, C, R>}`
    : `${R}${P}${DropChar<K, C, "">}`
  : R;

知识点

  1. 字符串拼接 + 递归

2. Medium Minus One

题目要求

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

type cases = [
  Expect<Equal<MinusOne<1>, 0>>,
  Expect<Equal<MinusOne<55>, 54>>,
  Expect<Equal<MinusOne<3>, 2>>,
  Expect<Equal<MinusOne<100>, 99>>,
  Expect<Equal<MinusOne<1101>, 1100>>,
]

我的解答

type NumberToTuple<
  T extends number,
  U extends any[] = []
> = U["length"] extends T ? U : NumberToTuple<T, [1, ...U]>;

type MinusOne<
  T extends number,
  R extends number[] = NumberToTuple<T>
> = R extends [infer P, ...infer X] ? X["length"] : 0;

知识点

  1. 如果将一个数字扩展成一个数组,使用之前的length获取数组长度的方法和这个常量的数字通过extends进行比较即可
  2. 还是利用length求得-1后的长度
  3. @todo:目前这个地方超过1000就会溢出了,所以其实写的还是不够完美,后面可以看看其他的更完美的方案

3. Medium Pick By Type

题目要求

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

interface Model {
  name: string
  count: number
  isReadonly: boolean
  isEnable: boolean
}

type cases = [
  Expect<Equal<PickByType<Model, boolean>, { isReadonly: boolean; isEnable: boolean }>>,
  Expect<Equal<PickByType<Model, string>, { name: string }>>,
  Expect<Equal<PickByType<Model, number>, { count: number }>>,
]

我的解答

type PickByType<T extends object, U, K extends keyof T = keyof T> = {
  [key in K extends K ? (T[K] extends U ? K : never) : never]: U;
};

知识点

  1. 关键在于如何将一个对象真实的key过滤出来,那些泛化的[key: string]过滤掉,使用K extends K这种方式