type-challenges [medium]

109 阅读2分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

0、前言

type-challenges

每天花几分钟练练ts...

1、获取函数返回类型

使用条件类型推断,利用infer声明返回的类型,T和Type是传入的函数,

type MyReturnType<T> = T extends (...args: any[]) => infer G ? G : never

// 源码
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
  ? Return
  : never;

2、实现 Omit

Omit 会创建一个省略 K 中字段的 T 对象。

type MyOmit<T, K extends keyof T> = {
  [P in Exclude<keyof T, K>]: T[P]
}

// 源码
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

3、Readonly 2

type MyReadonly2<T, K extends (keyof T) = keyof T> = Omit<T, K> & {readonly [id in K]: T[id] }

type MyReadonly2<T, K extends keyof T = keyof T> = Readonly<Pick<T, K>> & Omit<T, K>

type MyReadonly2<T, K = keyof T> = {
  readonly [P in keyof T as P extends K ? P : never]: T[P]
} & {
  [P in keyof T as P extends K ? never: P]: T[P]
}

type MyReadonly2<T, K> = { [Q in Exclude<keyof T, K>]: T[Q] } & {
  readonly [P in Extract<keyof T, K>]: T[P];
};

4、深度 Readonly

它将对象的每个参数及其子对象递归地设为只读

type DeepReadonly<T extends Record<string, any>> = T extends Function
  ? T
  : T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]> } : T;

----
type DeepReadonly<T extends Object> = {
  readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>
}
  
----
type DeepReadonly<T> = {
  readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>
}

----
type IsArray = T extends Array ? true : false;
type IsFunction = T extends Function ? true : false;
type IsObject = T extends { [key: string]: any } ? IsFunction extends true ? false : true : false;
type NeedRecursive = IsArray extends true ? true : IsObject extends true ? true : false;

type DeepReadonly = {
readonly [key in keyof T]: NeedRecursive<T[key]> extends true ? DeepReadonly<T[key]>: T[key]
}

5、元组转合集

type TupleToUnion<T extends unknown[]> = T[number]

----
type TupleToUnion<T extends any[]> = T[number]

type arr = [123, '456', true]
type a = arr[number]  // arr[number]  返回得到一个  union 类型   true | 123 | "456"

测试:

type Arr = ["1", "2", "3"];
type TupleToUnion<T extends unknown[]> = T[number]
type e = TupleToUnion<Arr>;
// 相当于
type e = "1" | "2" | "3"
type Chainable<T = {}> = {
  option<K extends string, V = any>(key: K extends keyof T ? never : K, value: V): Chainable<T & { [O in K]: V }>
  get(): T
}

6、可串联构造器

declare const config: Chainable

const result = config
  .option('foo', 123)
  .option('name', 'type-challenges')
  .option('bar', { value: 'Hello World' })
  .get()

// 期望 result 的类型是:
interface Result {
  foo: number
  name: string
  bar: {
    value: string
  }
}

type Merge<T, U> = {
  [P in Exclude<keyof T, keyof U>]: T[P]
} & {
  [G in keyof U]: U[G]
}
type Chainable<T = {}> = {
  option<K extends string, V>(key: K, value: V): Chainable<Merge<T, {[P in K]: V}>>
  get(): T
}

7、Last of Array

实现一个通用Last<T>,它接受一个数组T并返回其最后一个元素的类型。

例如

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]

type tail1 = Last<arr1> // expected to be 'c'
type tail2 = Last<arr2> // expected to be 1

实现

type arr1 = ["a", "b", "c"];

// infer 关键字声明了一个新的类型变量B
type Last<T extends any[]> = T extends [...infer A, infer B] ? B : never;

// 或者
type Last<T extends any[]> = T extends [...any, infer L] ? L : never;

// 或者
type Last<T extends any[]> = [any, ...T][T["length"]];

type Res = Last<arr1>;
// 相当于 type Res = "c";

8、出堆

实现一个通用Pop,接受一个数组T并返回一个没有最后一个元素的数组。

type arr1 = ["a", "b", "c"];

type Pop<T extends any[]> = T extends [...infer U, any] ? U : never

type Res = Pop<arr1>;

// 相当于

type Res = ["a", "b"]