# 一、ts 内置工具

提示

官方地址:utility Types (opens new window)

# 1、Partial<Type>

官方描述:Partial (opens new window)

构造一个类型,并将 Type 的所有属性都设置为可选。

interface Foo {
  a: number
  b?: number
}

type PartialFoo = Partial<Foo> // { a?: number, b?: number}
实现原理
type Partial<T> = {
  [P in keyof T]?: T[p]
}

# 2、Required<Type>

interface Foo {
  a: number
  b?: number
}

type RequiredFoo = Required<Foo> // { a: number, b: number}
实现原理
type Required<T> = {
  [P in keyof T]-?: T[p]
}

# 3、Readonly<Type>

interface Foo {
  a: number
  b?: number
}

type ReadonlyFoo = Readonly<Foo> // { readonly a: number,readonly b?: number | undefined}
实现原理
type Readonly<T> = {
  readonly [P in keyof T]: T[p]
}

# 4、Exclude<T, E>

从类型 T 中排除掉 T、E 两者间的交集部分

// 使用1
type Foo = 'a' | 'b' | 'c'
type Bar = Exclude<Foo, 'a'> // "b" | "c"

// 使用2
type Foo = Exclude<1 | 2, 1 | 3> // 2
实现原理
type Exclude<T, E> = T extends E ? never : T

# 5、Extract<T, U>

提取 T、U 两者间的交集部分 (和 Exclude 相反)

// 使用1
type Foo = 'a' | 'b' | 'c'
type Bar = Extract<Foo, 'a'> // "a"

// 使用2
type Foo = Extract<1 | 2, 1 | 3> // 1
实现原理
type Extract<T, U> = T extends U ? T : never

# 6、NonNullable<Type>

排除掉 null 和 undefined 类型

type T0 = NonNullable<string | number | undefined>
// type T0 = string | number

type T1 = NonNullable<string[] | null | undefined>
// type T1 = string[]
实现原理
type NonNullable<T, U> = T extends null | undefined ? never : T

# 7、ThisType<Type>

interface IState {
  name: string
  age: number
}

interface IStore {
  state: IState
  eating: () => void
  running: () => void
}

// 方式2
const store: IStore & ThisType<IState> = {
  state: {
    name: 'lencamo',
    age: 20
  },
  // eating: function (this: IState) {  // 方式1
  //   console.log(this.name)  // 这样就可以不使用 this.state.name 了
  // },
  running: function () {
    console.log(this.age)
  }
}

store.eating.call(store.state)

# 二、类型继承 extends

  提前说明一下,下面部分的内容最好是已经看过了面向对象部分的:泛型约束、类型映射等知识

# extends

SomeType extends OtherType ? TrueType : FalseType
type IDType = number | string

type ResType = number extends IDType ? true : false
关于函数重载的思考
function sum(num1, num2) {
  return num1 + num2
}
  • 函数重载
function sum(num1: number, num2: nubmer): number
function sum(num1: string, num2: string): string
  • 使用泛型
// 联合类型中的一个
function sum<T extends number | string>(num1: T, num2: T): T extends number ? number : string

# 1、Record<Keys, Type>

  用于仅对象和 keys 映射构造一个对象类型

interface CatInfo {
  age: number
  breed: string
}

type CatName = 'miffy' | 'boris' | 'mordred'

const cats: Record<CatName, CatInfo> = {
  miffy: { age: 10, breed: 'Persian' },
  boris: { age: 5, breed: 'Maine Coon' },
  mordred: { age: 16, breed: 'British Shorthair' }
}
对 Record 的封装

Record<Keys, Type>

// 联合类型中的一个
type MyRecord<Keys extends keyof any, T> = {
  [P in Keys]: T
}
  • 使用
interface CatInfo {
  age: number
  breed: string
}

type CatName = 'miffy' | 'boris' | 'mordred'

const cats: Record<CatName, CatInfo> = {
  miffy: { age: 10, breed: 'Persian' },
  boris: { age: 5, breed: 'Maine Coon' },
  mordred: { age: 16, breed: 'British Shorthair' }
}

cats.boris

# 2、Pick<Type, Keys>

  在对象类型中选择一部分 key 作为一个新的对象类型

interface Todo {
  title: string
  description: string
  completed: boolean
}

type TodoPreview = Pick<Todo, 'title' | 'completed'>

const todo: TodoPreview = {
  title: 'Clean room',
  completed: false
}

todo
对 Pick 的封装

Pick<Type, Keys>

// 联合类型中的一个
type MyPick<T, Keys extends keyof T> = {
  [P in Keys]: T[P]
}
  • 使用
interface Todo {
  title: string
  description: string
  completed: boolean
}

type TodoPreview = Pick<Todo, 'title' | 'completed'>

const todo: TodoPreview = {
  title: 'Clean room',
  completed: false
}

todo

# 3、Omit<Type, Keys>

  和 Pick 的作用相反

// 略
对 Omit 的封装

Omit<Type, Keys>

Omit 和 Pick 的作用是相反的

// 联合类型中的一个
type MyOmit<T, Keys extends keyof T> = {
  // 先拷贝,后筛选(类似于Exclude<T, U>的实现)
  [(P in keyof T) as P extends Keys ? never : P ]: T[P]
}

# 三、类型推断 infer

# 1、ReturnType<Type>

  ReturnType 是用于获取函数返回值类型

  • 简单场景
function foo() {
  return 'lencmao'
}

// 常规
type FooReturnType = ReturnType<typeof foo>
// 使用ts内置工具
type FooReturnType = ReturnType<foo>
  • 复杂场景
type T1 = ReturnType<(s: string) => void>
// type T1 = void

type T2 = ReturnType<() => string>
// type T2 = string

type T3 = ReturnType<<T extends U, U extends number[]>() => T>
// type T3 = number[]
对 ReturnType 的封装

ReturnType<Type>

type CalcFnType = (num1: nubmer, num2: nubmer) => nubmer

// 推断返回值类型
type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R
  ? R
  : never

type CalcReturnType = MyReturnType<CalcFnType>

# 2、Parameters<Type>

  Parameters 是用于获取函数参数类型

type T0 = Parameters<() => string>
// type T0 = []

type T1 = Parameters<(s: string) => void>
// type T1 = [s: string]

type T2 = Parameters<<T>(arg: T) => T>
// type T2 = [arg: unknown]
对 Parameters 的封装

Parameters<Type>

type CalcFnType = (num1: nubmer, num2: nubmer) => nubmer

// 推断参数类型
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any
  ? P
  : never

type CalcReturnType = MyParameters<CalcFnType>

# 3、InstanceType<Type>

  InstanceType 用于获取构造函数创建的实例对象的类型

  • 获取实例对象类型
class C {
  x = 0
  y = 0
}

type T0 = InstanceType<typeof C>
// type T0 = C
<template>
  <Son ref="sonRef" />
</template>

<script setup lang="ts">
import Son from './Son.vue'

const sonRef = ref<InstanceType<typeof Son>>()

//……
</script>
  • 使用实例对象类型
function factory<T extends new (...args: any[]) => any>(ctor: T): InstanceType<T> {
  return new ctor()
}

const T1 = factory(C)
对 InstanceType 的封装

InstanceType<Type>

class Person {}

type MyInstanceType<T extends new (...args: any[]) => any> = T extends new (
  ...args: any[]
) => infer R
  ? R
  : never

type p1 = MyInstanceType<typeof Person>

# 四、类型分发

  当我们在泛型中使用条件类型的时候,如果传入的是一个联合类型,就会变成分发的

  • 普通使用(不分发)
type toArray<T> = T[]

type NumArray = toArray<number>

type NumArray = toArray<string | number>
// (string | number)[]
  • 特殊使用(分发)
// 泛型中使用条件类型
type toArray<T> = T extends any ? T[] : never

type NumArray = toArray<number>

// 传入的是一个联合类型
type NumArray = toArray<string | number>
// string[] | number[]
更新于 : 8/7/2024, 2:16:31 PM