TS内置工具类型

TypeScript 官方提供了许多内置类型,无需导入即可使用,基于这些类型工具,我们可以快速的处理各种类型以及生成新的类型,以下列举了几个实用类型的使用方式及对应源码:

Partial<T>

将类型参数 T 中的所有属性变为可选属性

typescript 复制代码
// 源码
type Partial<T> = {
  [P in keyof T]?: T[P]
}

interface User {
  name: string
  age: number
}

type T = Partial<User>

// 等价于
type T = {
  name?: string
  age?: number
}

Required<T>

将类型参数 T 中的所有属性变为必选属性,,移除了 T 每个属性上的可选属性修饰符 ?

typescript 复制代码
// 源码
type Required<T> = {
  [P in keyof T]-?: T[P]
}

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

type T = Required<User>

// 等价于
type T = {
  name: string
  age: number
}

Readonly<T>

将类型参数 T 中的所有属性变为只读属性

typescript 复制代码
// 源码
type Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

interface User {
  name: string
  age: number
}

type T = Readonly<User>

// 等价于
type T = {
  readonly name: string
  readonly age: number
}

Record<K,T>

类型参数 K 为对象属性名的联合类型,类型参数 T 为对象属性值的类型,因为类型参数 K 是用作对象属性名类型,所以实际类型参数 K 必须能够赋值给 string | number | symbol 类型,只有这些类型能够作为对象属性名类型。

个人理解:批量的为对象的属性声明类型,K 为属性名的联合类型。其中对象的所有的属性名均来自 KT 为属性值类型,将对象中的所有属性都声明为 T 类型

typescript 复制代码
// 源码
type Record<K extends keyof any, T> = {
  [P in K]: T
}

interface Position {
  x: string
  y: string
}

type T = Record<keyof Position, number>

// 等价于 
type T = {
  x: number
  y: number
}

Exclude<T,U>

从联合类型 T 中删除可以赋值给联合类型 U 的类型

typescript 复制代码
// 源码
// 先判断类型 T 是否兼容类型 U,是则返回 never 类型,否则返回 T 类型,由于 never 是任何其他类型的子类型,它跟其他类型组成联合类型时,可以直接将never类型从联合类型中"消掉",因此 Exclude<T, U> 就相当于删除兼容的类型,剩下不兼容的类型
type Exclude<T, U> = T extends U ? never : T

interface User {
  name: string
  age: number
}

type T = Exclude<keyof User, 'name'>

// 等价于
type T = 'age'

type T2 = Exclude<keyof User, 'name' | 'email'>

// 等价于
type T2 = 'age'

Extract<T,U>

Extract<T, U> 工具类型与 Exclude<T, U> 工具类型是互补的,该类型能够从联合类型 T 中挑选可以赋值给联合类型 U 的类型

typescript 复制代码
// 源码
type Extract<T, U> = T extends U ? T : never

interface User {
  name: string
  age: number
}

type T = Extract<keyof User, 'name'>

// 等价于
type T = 'name'

type T2 = Extract<keyof User, 'name' | 'email'>

// 等价于
type T2 = 'name'

Pick<T,K>

从已有对象类型中挑选一个或多个指定的属性并保留它们的类型和修饰符,然后构造出一个新的对象类型。类型参数 T 为对象类型,类型参数 K 为从类型参数 T 中挑选的属性名类型

typescript 复制代码
// 源码
type Pick<T, K extends keyof T> = {
  [P in K]: T[P]
}

interface User {
  name: string
  age?: number
}

type T = Pick<User, 'age'>

// 等价于
type T = {
  age?: number
}

type T2 = Pick<User, 'name' | 'age'>

// 等价于
type T2 = {
  name: string
  age?: number
}

Omit<T,K>

Omit<T, K> 工具类型与 Pick<T, K> 工具类型是互补的,它能够从已有对象类型中剔除给定的属性,然后构建出一个新的对象类型。类型参数 T 为对象类型,类型参数 K 为从类型参数 T 中挑选的需要剔除的属性名类型,也可以是对象类型 T 中不存在的类型

typescript 复制代码
// 源码
type Omit<T, K extends keyof any> = {
  [P in Exclude<keyof T, K>]: T[P]
}

interface User {
  name: string
  age: number
}

type T = Omit<User, 'age'>

// 等价于
type T = {
  name: string;
}

type T2 = Omit<User, 'email'>

// 等价于
type T2 = {
  name: string;
  age: number;
}

NonNullable<T>

从联合类型参数 T 中剔除 null 类型和 undefined 类型,也就是将类型 T 变为一个非空类型

typescript 复制代码
// 源码
// T & {}等同于求 T & Object 的交叉类型。由于 TypeScript 的非空值都属于 Object 的子类型,所以会返回自身;而 null 和 undefined 不属于Object,会返回 never 类型
type NonNullable<T> = T & {}

// 也可以这样写
type NonNullable<T> = T extends null | undefined ? never : T

type K = number | string | null | undefined
type T = NonNullable<K>

// 等同于
type T = string | number

Parameters<T>

从函数类型 T 中提取参数类型并组成元祖类型返回

typescript 复制代码
// 源码
// infer 关键字用来定义泛型里面推断出来的类型参数,通常需要和 extends 关键字搭配使用
type Parameters<T extends (...args: any) => any> = T extends (
  ...args: infer P
) => any
  ? P
  : never

type T = Parameters<(a: number, b: string) => string>

// 等价于
type T = [a: number, b: string]

type T2 = Parameters<() => any>

// 等价于
type T2 = []

type T3 = Parameters<<T>(arg: T) => T>

// 等价于
type T3 = [arg: unknown]

如果函数类型 T 不是带有参数的函数形式,会报错

typescript 复制代码
// 以下类型会报错
type T1 = Parameters<string>
type T2 = Parameters<Function>

anynever 的特殊情况

typescript 复制代码
type T1 = Parameters<any>

// 等价于
type T1 = unknown[]

type T2 = Parameters<never>

// 等价于
type T2 = never

ConstructorParameters<T>

提取构造方法 T 的参数类型,并组成元组类型返回

typescript 复制代码
// 源码
type ConstructorParameters<T extends abstract new (...args: any) => any> =
  T extends abstract new (...args: infer P) => any ? P : never

type T = ConstructorParameters<new (a: number, b: number) => object>

// 等价于
type T = [a: number, b: number]

如果参数类型不是构造方法,就会报错

typescript 复制代码
// 以下代码会报错
type T1 = ConstructorParameters<string>
type T2 = ConstructorParameters<Function>

anynever 的特殊情况

typescript 复制代码
type T1 = ConstructorParameters<any>

// 等价于
type T1 = unknown[]

type T2 = ConstructorParameters<never>

// 等价于
type T2 = never

它可以返回一些内置构造方法的参数类型

typescript 复制代码
type T1 = ConstructorParameters<ErrorConstructor> 
// type T1 = [message?: string | undefined]

type T2 = ConstructorParameters<FunctionConstructor>
// type T2 = string[]

type T3 = ConstructorParameters<RegExpConstructor> 
// type T3 = [pattern: string | RegExp, flags?: string | undefined]

ReturnType<T>

获取函数类型 T 的返回值类型

typescript 复制代码
// 源码
type ReturnType<T extends (...args: any) => any> = T extends (
  ...args: any
) => infer R
  ? R
  : any

type T = ReturnType<() => { a: number; b: number }>

// 等价于
type T = {
  a: number
  b: number
}

如果参数类型是 T,返回值取决于泛型类型,如果泛型不带限制条件,就会返回 unknown

typescript 复制代码
type T1 = ReturnType<<T>() => T>
  
// 等价于
type T1 = unknown

type T2 = ReturnType<<T extends U, U extends number[]>() => T>

// 等价于
type T2 = number[]

如果类型不是函数,会报错

typescript 复制代码
// 以下代码会报错/*  */
type T1 = ReturnType<number>
type T2 = ReturnType<Function>

anynever 的特殊情况,分别返回 anynever

typescript 复制代码
type T1 = ReturnType<any>

// 等价于
type T1 = any

type T2 = ReturnType<never>

// 等价于
type T2 = never

InstanceType<T>

获取构造函数的返回值类型,即实例类型

typescript 复制代码
// 源码
type InstanceType<T extends abstract new (...args: any) => any> =
  T extends abstract new (...args: any) => infer R ? R : any

class User {
  name: 'kunkun'
  age: 18
}

type T = InstanceType<typeof User>

// 等价于
type T = User

如果类型参数不是构造方法,就会报错

typescript 复制代码
// 以下代码会报错
type T1 = InstanceType<string> 
type T2 = InstanceType<Function> 

anynever 的特殊情况,分别返回 anynever

typescript 复制代码
type T1 = InstanceType<any>

// 等价于
type T1 = any

type T2 = InstanceType<never>

// 等价于
type T2 = never

它可以返回一些内置构造函数类型

typescript 复制代码
type T1 = InstanceType<ErrorConstructor>

// 等价于
type T1 = Error

type T2 = InstanceType<FunctionConstructor>

// 等价于
type T2 = Function

type T3 = InstanceType<RegExpConstructor>

// 等价于
type T3 = RegExp

ThisParameterType<T>

获取函数类型 Tthis 参数的类型

typescript 复制代码
type ThisParameterType<T> = T extends (this: infer U, ...args: never) => any
  ? U
  : unknown

function fn(this: number) {
  return this.toString()
}

type T = ThisParameterType<typeof fn>

// 等价于
type T = number

如果函数中没有 this 参数,则返回 unknown

typescript 复制代码
function fn(a: number) {}

type T = ThisParameterType<typeof fn>

// 等价于
type T = unknown

OmitThisParameter<T>

从函数类型 T 中剔除 this 参数类型

typescript 复制代码
// 源码
type OmitThisParameter<T> = unknown extends ThisParameterType<T>
  ? T
  : T extends (...args: infer A) => infer R
  ? (...args: A) => R
  : T

function fn(this: number, a: number) {
  return this.toString()
}

type T = OmitThisParameter<typeof fn>

// 等价于
type T = (a: number) => string

ThisType<T>

TypeScript 中,默认对象中方法中的 thisany 类型,可以使用 ThisType<T> 声明 this 类型,在使用该类型工具时,需要打开 noImplicitThis 设置

tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "noImplicitThis": true 
  }
}
typescript 复制代码
// 源码
interface ThisType<T> {}

interface User {
  name: string
  age: number
  hobby: string[]
  sayHi: () => void
}

type T = ThisType<User>

// ThisType<User> 使得 sayHi 方法内部的 this 被明确为 User 类型
const user: User & ThisType<User> = {
  name: 'kunkun',
  age: 18,
  hobby: ['唱', '跳', 'rap'],
  sayHi: function () {
    console.log(
      `你好,我是${this.name},今年${this.age}
        岁,我的爱好是:${this.hobby.join(',')}`
    )
  },
}

Awaited<T>

用于获取 Promise 的返回值类型,适合在描述 then 方法和 await 命令的参数类型

typescript 复制代码
// 源码
type Awaited<T> = T extends null | undefined ? T : T extends object & {
    then(onfulfilled: infer F, ...args: infer _): any;
} ? F extends (value: infer V, ...args: infer _) => any ? Awaited<...> : never : T

type T = Awaited<Promise<string>>

// 等价于
type T = string

它也可以返回多重 Promise 的返回值类型

typescript 复制代码
type T = Awaited<Promise<Promise<number>>>

// 等价于
type T = number

如果它的类型参数不是 Promise 类型,那么就会原样返回

typescript 复制代码
type T2 = Awaited<boolean | Promise<number>>

// 等价于
type T2 = number | boolean

字符串类型工具

typescript 复制代码
type T = 'hello'

// Uppercase<T>:将字符串类型的每个字符转为大写
type T2 = Uppercase<T>
// type T2 = "HELLO"

// Lowercase<T>:将字符串的每个字符转为小写
type T3 = Lowercase<T2>
// type T3 = "hello"

// Capitalize<T>:将字符串的第一个字符转为大写
type T4 = Capitalize<T>
// type T4 = "Hello"

// Uncapitalize<T>:将字符串的第一个字符转为小写
type T5 = Uncapitalize<T2>
// type T5 = "hELLO"
相关推荐
好_快4 分钟前
Lodash源码阅读-类型判断部分总结
前端·javascript·源码阅读
恋猫de小郭1 小时前
再聊 Flutter Riverpod ,注解模式下的 Riverpod 有什么特别之处,还有发展方向
android·前端·flutter
Aress"1 小时前
【2025前端高频面试题——系列一之MVC和MVVM】
前端·mvc
Json____1 小时前
好玩的谷歌浏览器插件-自定义谷歌浏览器光标皮肤插件-Chrome 的自定义光标
前端·chrome·谷歌插件·谷歌浏览器插件·光标皮肤·自定义光标
蜡笔小新星2 小时前
Flask项目框架
开发语言·前端·经验分享·后端·python·学习·flask
Fantasywt6 小时前
THREEJS 片元着色器实现更自然的呼吸灯效果
前端·javascript·着色器
IT、木易6 小时前
大白话JavaScript实现一个函数,将字符串中的每个单词首字母大写。
开发语言·前端·javascript·ecmascript
张拭心8 小时前
2024 总结,我的停滞与觉醒
android·前端
念九_ysl8 小时前
深入解析Vue3单文件组件:原理、场景与实战
前端·javascript·vue.js
Jenna的海糖8 小时前
vue3如何配置环境和打包
前端·javascript·vue.js