类型体操刷题系列(十七)— RequiredByKeys/Mutable/OmitByType

265 阅读1分钟

目的

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

ts 类型体操 github 我的解答

题目大纲

  1. Medium Required By Keys
  2. Medium Mutable
  3. Medium Omit By Type

01. Medium Required By Keys

题目要求

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

interface User {
  name?: string;
  age?: number;
  address?: string;
}

interface UserRequiredName {
  name: string;
  age?: number;
  address?: string;
}

interface UserRequiredNameAndAge {
  name: string;
  age: number;
  address?: string;
}

type cases = [
  Expect<Equal<RequiredByKeys<User, "name">, UserRequiredName>>,
  Expect<Equal<RequiredByKeys<User, "name" | "unknown">, UserRequiredName>>,
  Expect<Equal<RequiredByKeys<User, "name" | "age">, UserRequiredNameAndAge>>,
  Expect<Equal<RequiredByKeys<User>, Required<User>>>
];

我的答案

type MyRequired<T extends object> = {
  [K in keyof T]-?: T[K];
};

type RequiredByKeys<
  T extends object,
  K extends any = never,
  R extends object = isNever<K> extends true
    ? MyRequired<T>
    : {
        [key in Exclude<keyof T, K>]?: MyRequired<T>[key];
      } & {
        [key in Extract<K, keyof T>]: MyRequired<T>[key];
      }
> = {
  [key in keyof R]: R[key];
};

知识点 Q1: 如何去除 typescript 中的关键字,比如?readonly等 A1:使用-这个关键字

2. Medium Mutable

题目要求

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

interface Todo1 {
  title: string;
  description: string;
  completed: boolean;
  meta: {
    author: string;
  };
}

type cases = [Expect<Equal<Mutable<Readonly<Todo1>>, Todo1>>];

我的解答

type Mutable<R extends object> = {
  -readonly [K in keyof Readonly<R>]: R[K];
};

知识点

  1. 使用-关键字可以将一些修饰符减掉,达到我们的目的

3. Medium Omit By Type

题目要求

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

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

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

type CC = OmitByType<Model, boolean>;

我的解答

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

知识点

  1. 关键在于如何将一个对象真实的key过滤出来,那些泛化的[key: string]过滤掉,使用K extends K这种方式
  2. 如果在遍历对象的时候剔除掉一个key,key返回是never就不会被计入其中