TypeScript 杂记二 《类型体操》

Posted 左手121

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript 杂记二 《类型体操》相关的知识,希望对你有一定的参考价值。

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

以上是关于TypeScript 杂记二 《类型体操》的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 学习笔记 — 模板字符串和类型体操(十五)

TypeScript 杂记一

TypeScript 杂记一

TypeScript 学习笔记 — 类型推断和类型保护

TypeScript——类型检查机制

TypeScript:推断嵌套联合类型的类型