欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TypeScript 杂记二 《类型体操》

程序员文章站 2022-03-01 12:53:26
...

TypeScript 杂记二 《类型体操》

type-challenges 题目

前提

type A = keyof any
// ===
type A = string | number | symbol

// infer 表示待推断的类型,如下内置类型
type ReturnType<T> = T extends (...args: any[]) => infer P ? P : any
type B = ReturnType<(value: string) => string>
// ===
type B = string

type Func = () => void
type C = keyof Func
// ===
type C = never

class Class {}
type C = keyof Class
// ===
type C = never

Pick<T, K>

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

Readonly

type _Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

Partial

type _Partial<T> = {
  [P in keyof T]?: T[P]
}

Required

type _Required<T> = {
  [P in keyof T]-?: T[P]
}

Record<T, K>

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

Exclude<T, K>

type _Exclude<T, K> = T extends K ? never : T

Extract<T, K>

type _Extract<T, K> = T extends K ? T : never

Omit<T, K>

type _Omit<T, K extends keyof any> = _Pick<T, _Exclude<keyof T, K>>

First

实现一个通用 First<T>,它接受一个数组 T 并返回它的第一个元素的类型

type First<T extends any[]> = T extends [] ? never : T[0]

Last

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

type First<T extends any[]> = T extends [...infer O, infer R] ? R : never

Readonly2<T, K>

实现一个通用的 Readonly2<T, K>,K 指定应设置为 Readonly 的 T 的属性集。如果未提供 K,则应使所有属性都变为只读,就像普通的 Readonly一样

// 自己写的
type Readonly2<T, K extends keyof T = any> = K extends never
  ? Readonly<T>
  : {
      readonly [P in K]: T[P]
    } & {
      [P in Exclude<keyof T, K>]: T[P]
    }

// 别人的精简版
type Readonly2<T, K extends keyof T = keyof T> = {
  readonly [P in K]: T[P]
} & Omit<T, K>

DeepReadonly

实现一个通用的 DeepReadonly<T>,它将对象的每个参数及其子对象递归地设为只读

// 满足简单数据结构
type DeepReadonly<T> = {
  readonly [P in keyof T]: DeepReadonly<T[P]>
}
// 处理函数和类,原因查看前提的内容
type DeepReadonly<T> = keyof T extends never
  ? T
  : {
      readonly [P in keyof T]: DeepReadonly<T[P]>
    }

Trim

type trimed = Trim<' Hello World '> // expected to be 'Hello World'

// 处理左侧的空格和换行,infer 请查看前提
// 一个一个递归处理
type TrimL<T extends string> = T extends `${' ' | '\t' | '\n'}${infer S}`
  ? TrimL<S>
  : T
// 同理处理右侧
type TrimR<T extends string> = T extends `${infer S}${' ' | '\t' | '\n'}`
  ? TrimR<S>
  : T
type Trim<T extends string> = TrimL<TrimR<T>>

// 整合起来
type Trim<T extends string> = T extends `${' ' | '\t' | '\n'}${infer L}`
  ? Trim<L>
  : T extends `${infer R}${' ' | '\t' | '\n'}`
  ? Trim<R>
  : T

vue

实现类似 Vue 的类型支持的简化版本

const instance = SimpleVue({
  data() {
    return {
      firstname: 'Type',
      lastname: 'Challenges',
      amount: 10,
    }
  },
  computed: {
    fullname() {
      return this.firstname + ' ' + this.lastname
    },
  },
  methods: {
    hi() {
      alert(this.fullname.toLowerCase())
    },
  },
})
type ComputedReturn<T> = {
  [K in keyof T]: T[K] extends () => infer R ? R : never
}
declare function SimpleVue<D, C, M>(options: {
  data?(this: {}): D
  computed?: C & ThisType<D & ComputedReturn<C> & M>
  methods?: M & ThisType<D & ComputedReturn<C> & M>
}): D & ComputedReturn<C> & M