类型体操刷题系列(十四)— ReplaceKey/RemoveIndex/PercentageParse

394 阅读2分钟

目的

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

ts 类型体操 github 我的解答

题目大纲

  1. Medium Replace Key
  2. Medium Remove Index Signature
  3. Medium Percentage Parse

01. Medium ReplaceKey

题目要求

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

type NodeA = {
  type: 'A'
  name: string
  flag: number
}

type NodeB = {
  type: 'B'
  id: number
  flag: number
}

type NodeC = {
  type: 'C'
  name: string
  flag: number
}

type ReplacedNodeA = {
  type: 'A'
  name: number
  flag: string
}

type ReplacedNodeB = {
  type: 'B'
  id: number
  flag: string
}

type ReplacedNodeC = {
  type: 'C'
  name: number
  flag: string
}

type NoNameNodeA = {
  type: 'A'
  flag: number
  name: never
}

type NoNameNodeC = {
  type: 'C'
  flag: number
  name: never
}

type Nodes = NodeA | NodeB | NodeC
type ReplacedNodes = ReplacedNodeA | ReplacedNodeB | ReplacedNodeC
type NodesNoName = NoNameNodeA | NoNameNodeC | NodeB

type cases = [
  Expect<Equal<ReplaceKeys<Nodes, 'name' | 'flag', {name: number; flag: string}>, ReplacedNodes>>,
  Expect<Equal<ReplaceKeys<Nodes, 'name', {aa: number}>, NodesNoName>>,
]

我的答案

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

知识点

  1. 如果一个 key 不想返回对应的值的时候,可以直接返回 never
  2. 直接 map 对象然后修改对应key的类型即可

2. Medium RemoveIndex

题目要求

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

type Foo = {
  [key: string]: any;
  foo(): void;
}

type Bar = {
  [key: number]: any;
  bar(): void;
}

type Baz = {
  bar(): void;
  baz: string
}

type cases = [
  Expect<Equal< RemoveIndexSignature<Foo>, { foo(): void }>>,
  Expect<Equal< RemoveIndexSignature<Bar>, { bar(): void }>>,
  Expect<Equal< RemoveIndexSignature<Baz>, { bar(): void, baz: string }>>
]

我的解答

type RemoveIndexSignature<T extends any> = {
  [K in keyof T as string extends K
    ? never
    : number extends K
    ? never
    : K]: T[K];
};

知识点

  1. 想要判断一个对象的 key 是否是泛类型,可以用收窄的方式来做
  2. key的定义也可以使用 extends

3. Medium Percentage Parse

题目要求

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

type Case1 = ['', '', '']
type Case2 = ['+', '', '']
type Case3 = ['+', '1', '']
type Case4 = ['+', '100', '%']
type Case5 = ['', '10', '%']
type Case6 = ['-', '99', '%']

type cases = [
    Expect<Equal<PercentageParser<''>, Case1>>,
    Expect<Equal<PercentageParser<'+'>, Case2>>,
    Expect<Equal<PercentageParser<'+1'>, Case3>>,
    Expect<Equal<PercentageParser<'+100%'>, Case4>>,
    Expect<Equal<PercentageParser<'10%'>, Case5>>,
    Expect<Equal<PercentageParser<'-99%'>, Case6>>,
]

我的解答

type Notion = "+" | "-" | "%";

type PercentageParser<
  A extends string,
  R extends any[] = []
> = A extends `${infer P}${infer T}`
  ? P extends Notion
    ? Handler2<T, [...R, P]>
    : Handler2<A, [...R, ""]>
  : Handler2<A, [...R, ""]>;

type Handler2<T extends string, R extends any[] = []> = T extends `${infer X}%`
  ? [...R, X, "%"]
  : T extends string
  ? [...R, T, ""]
  : [...R, "", ""];

知识点

  1. 字符串拼接的判断以及递归的使用