类型体操刷题系列(二十)— BemStyleString/InOrderTraversal/Flip

906 阅读1分钟

目的

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

题目大纲

  1. Medium Bem Style String
  2. Medium In Order Traversal
  3. Medium Flip

01. Medium BemStyleString

题目要求

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

type cases = [
  Expect<Equal<BEM<'btn', ['price'], []>, 'btn__price'>>,
  Expect<Equal<BEM<'btn', ['price'], ['warning', 'success']>, 'btn__price--warning' | 'btn__price--success' >>,
  Expect<Equal<BEM<'btn', [], ['small', 'medium', 'large']>, 'btn--small' | 'btn--medium' | 'btn--large' >>,
]


我的答案

type BEM<
  B extends string,
  E extends string[],
  M extends string[]
> = E["length"] extends 0
  ? M["length"] extends 0
    ? B
    : M extends (infer P)[]
    ? P extends string
      ? `${B}--${P}`
      : B
    : B
  : E extends (infer P)[]
  ? P extends string
    ? M["length"] extends 0
      ? `${B}__${P}`
      : M extends (infer R)[]
      ? R extends string
        ? `${B}__${P}--${R}`
        : B
      : B
    : B
  : B;

知识点

  1. 各种通过extends对关键结果进行判断即可
  2. 通过length来判断某一个数组为空

2. Medium In Order Traversal

题目要求

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

const tree1 = {
  val: 1,
  left: null,
  right: {
    val: 2,
    left: {
      val: 3,
      left: null,
      right: null,
    },
    right: null,
  },
} as const

const tree2 = {
  val: 1,
  left: null,
  right: null,
} as const

const tree3 = {
  val: 1,
  left: {
    val: 2,
    left: null,
    right: null,
  },
  right: null,
} as const

const tree4 = {
  val: 1,
  left: null,
  right: {
    val: 2,
    left: null,
    right: null
  }
} as const

type cases = [
  Expect<Equal<InorderTraversal<null>, []>>,
  Expect<Equal<InorderTraversal<typeof tree1>, [1, 3, 2]>>,
  Expect<Equal<InorderTraversal<typeof tree2>, [1]>>,
  Expect<Equal<InorderTraversal<typeof tree3>, [2, 1]>>,
  Expect<Equal<InorderTraversal<typeof tree4>, [1, 2]>>,
]

我的解答

interface TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
}

type InorderTraversal<T extends TreeNode | null> = T extends TreeNode
  ? T["left"] extends never
    ? [T["val"]]
    : T["left"] extends TreeNode
    ? [
        ...InorderTraversal<T["left"]>,
        T["val"],
        ...InorderTraversal<T["right"]>
      ]
    : T["right"] extends TreeNode
    ? [T["val"], ...InorderTraversal<T["right"]>]
    : [T["val"]]
  : [];

知识点

  1. 一个关于二叉树的后序遍历,只要知道遍历方法就能做出来~
  2. 关于类型推断的遍历

3. Medium Flip

题目要求

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

type cases = [
  Expect<Equal<{a: 'pi'}, Flip<{pi: 'a'}>>>,
  Expect<NotEqual<{b: 'pi'}, Flip<{pi: 'a'}>>>,
  Expect<Equal<{3.14: 'pi', true: 'bool'}, Flip<{pi: 3.14, bool: true}>>>,
  Expect<Equal<{val2: 'prop2', val: 'prop'}, Flip<{prop: 'val', prop2: 'val2'}>>>,
]

我的解答

type TransKeyToString<T> = T extends boolean | string | number ? `${T}` : "";

type Flip<
  T extends object,
  K extends keyof T = keyof T,
  V extends T[K] = T[K]
> = {
  [key in TransKeyToString<V>]: K extends K
    ? TransKeyToString<T[K]> extends key
      ? K
      : never
    : never;
};

知识点

  1. 如果不想返回某个类型,可以返回never
  2. 使用K extends将泛型key删除