夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • TypeScript基础

    • TypeScript笔记
    • tsconfig.json配置
    • Record对象键值定义
    • 对象的方式描述类型
    • implements和extends
    • interface和type
    • keyof和typeof
    • Partial详解
    • 常用泛型工具
      • Typescript泛型工具
        • `Partial<T>` -可选
        • `Record<K,T>` -对象约束
        • `Readonly<T>` -只读
        • `Required<T>` -必选
        • `Pick<T,K>` -指定属性范围
        • `Exclude<T,K>` -剔除属性(联合类型)
        • `Extract<T,K>` -获取交叉属性
        • `Omit<T,K>` -剔除属性(对象类型)
        • `ReturnType<T>` -获取函数返回值类型
        • `Parameters<T>` -获取函数参数类型
        • `InstanceType<T>` -获取构造函数的类型
        • ConstructorParameters<T> -获取构造函数参数
  • TypeScript进阶

  • TS 从零实现 axios

  • 《TypeScript》
  • TypeScript基础
夜猫子
2022-11-30
目录

常用泛型工具

# Typescript泛型工具

TS 内置了一些很强大的泛型工具,可以使我们可以很方便的进行类型定义。

# Partial<T> -可选

将传入的属性变为可选项

interface IPeople {
    title: string;
    name: string;
}

const people: Partial<IPeople> = {
    title: 'Delete inactive users'
};
1
2
3
4
5
6
7
8

源码:

type Partial<T> = {
    [P in keyof T]?: T[P];
};
1
2
3

# Record<K,T> -对象约束

类型参数K提供了对象属性名联合类型,类型参数T提供了对象属性的类型

// 将x, y 作为Person的key
type Peoples = Record<"x" | "y", string>;

const P: Peoples = {
    x: {
        name: '张三'
    },
    y: {
        name: '李四'
    }
}
1
2
3
4
5
6
7
8
9
10
11

源码:

通过 K extends keyof any 对泛型进行约束,约束在 any 的 key中, K可以是任意类型(联合类型、对象、枚举…),再通过映射对象类型 { P in K : T } ,将每一个属性成员转化为 T 类型

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
1
2
3

# Readonly<T> -只读

把传入的类型变为只读状态

interface Person {
  name: string;
  age: number;
}

const p: Readonly<Person> = {
    name: '张三',
    age: 22
}

p.name = '李四'; // 无法分配到 "name" ,因为它是只读属性
1
2
3
4
5
6
7
8
9
10
11

源码:

与 Partial 实现原理类似,通过映射对象类型 { P in K : T } 方式遍历获取其所有属性成员,再统一设置为 readonly

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
1
2
3

# Required<T> -必选

把传入的类型变为必选状态

interface Person {
    name?: string;
    age?: number;
}

const p: Required<Person> = {
    name: '张三',
    age: 22
}
1
2
3
4
5
6
7
8
9

源码:

与 Partial 实现原理类似,通过映射对象类型 { P in K : T } 方式遍历获取其所有属性成员, 再统一通过“-” 修饰符移除 “?” 修饰符,从而转变为必填状态

type Required<T> = {
    [P in keyof T]-?: T[P];
};
// -? 表示必选
1
2
3
4

# Pick<T,K> -指定属性范围

指定属性范围

interface IPerson {
    name: string;
    age: number;
}

type TP = Pick<IPerson, 'name'>;

const p: TP = {
    age: 22, // 对象文字可以只指定已知属性,并且“age”不在类型“TP”中
    name: '张三'
}
1
2
3
4
5
6
7
8
9
10
11

源码:

通过 K extends keyof T 进行泛型约束,将 K 被约束在 T 的key中,不能超出这个范围,再通过映射对象类型 { key in K : T[key] } ,来约束每一个属性成员。

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
1
2
3

# Exclude<T,K> -剔除属性(联合类型)

该工具类型能够从类型T中剔除所有可以赋值给类型U的类型

type T0 = Exclude<"a" | "b" | "c", "a">;
// 相当于 type T0 = "b" | "c"

type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
// 相当于 type T1 = "c"

type T2 = Exclude<string | number | (() => void), Function>;
// 相当于 type T2 = string | number	
1
2
3
4
5
6
7
8

注意:

// 条件类型作用于泛型内,且入参为联合类型(a|b)时,它们就会变成分布式的:
type Exclude<T, U> = T extends U ? never : T;

type Str = 'a' | 'b' | 'c';

type R = Exclude<'a' | 'd', Str>;

// 相当于
type R = Exclude<'a', Str> | Exclude<'d', Str>
// 也相当于
type R = never | 'd'
// 所以
type R = 'd'

//另外提一点,如果想避免这种行为,可以这样写;
type Exclude<T, U> = [T] extends [U] ? never : T;
//那
type Str = 'a' | 'b' | 'c';
type R = Exclude<'a' | 'd', Str>;
type R = never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

源码:

表示如果 T 是 U 的子类返回 never 类型,如果不是返回 T 类型。 当 T 为联合类型的时候,它会自动分发条件。

type Exclude<T, U> = T extends U ? never : T;
1

# Extract<T,K> -获取交叉属性

“Extract<T, U>”工具类型与“Exclude<T, U>”工具类型是互补的,它能够从类型T中获取所有可以赋值给类型U的类型

type T0 = Extract<'a' | 'b' | 'c', 'a' | 'f'>;
// 相当于 type T0 = 'a';

type T1 = Extract<string | (() => void), Function>;
// 相当于 type T1 = () => void;

type T2 = Extract<string | number, boolean>;
// 因为没有交集,相当于 type T2 = never;
1
2
3
4
5
6
7
8

源码:

与 Exclude<T, U> 实现方式类似

type Extract<T, U> = T extends U ? T : never;
1

# Omit<T,K> -剔除属性(对象类型)

在 T 中删除对应的 K

interface IPerson {
    name: string;
    age: number;
}

type TP = Omit<IPerson, 'age'>;

const p: TP = {
    name: '张三'
}
1
2
3
4
5
6
7
8
9
10

源码:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
1

# ReturnType<T> -获取函数返回值类型

该工具类型能够获取函数类型T的返回值类型

// string
type T0 = ReturnType<() => string>;

// { a: string; b: number }
type T1 = ReturnType<() => { a: string; b: number}>;
1
2
3
4
5

源码:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
// (...args: any) 表示可以提供any类型的任何数量的参数。因为存在数量未知的any参数,所以参数的类型是any的数组即 any[]。
// 第一个泛型表示 T 为一个有返回值的函数。
// 后面结果表示:如果 T 有返回值,结果为返回值 R ,否则返回 any。
1
2
3
4

infer:(推导泛型参数)

// infer 表示在 extends 条件语句中待推断的类型变量。
// 从返回值得到参数?
// 下面这个语句中infer P 表示待推断的函数参数(从T推导出P)。
type ParamType<T> = T extends (arg: infer P) => any ? P : T;
// 整句表示为:如果 T 能赋值给 (arg: infer P) => any,则结果是 (arg: infer P) => any 类型中的参数 P,否则返回为 T。
type numberPromise = Promise<number>;
type n = numberPromise extends Promise<infer P> ? P : never; // 推导出T是number
// 还有注意一点,infer 只能在 extends 的右边使用,infer P 的 P 也只能在条件类型为 True 的一边使用
1
2
3
4
5
6
7
8

# Parameters<T> -获取函数参数类型

// a:string
type T0 = ReturnType<(a:string) => any>;

// [a: string; b: number]
type T1 = ReturnType<(a: string; b: number) => any>;
1
2
3
4
5

源码:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
1

# InstanceType<T> -获取构造函数的类型

常见的使用有在 Vue 里获取子组件的类型

import MyModal from './MyModal.vue'
class C {
    x = 0;
    y = 0;
}
type T19 = InstanceType<typeof MyModal>; // MyModal extends Vue Component  
type T20 = InstanceType<typeof C>;  // C
type T21 = InstanceType<any>;  // any
type T22 = InstanceType<never>;  // any
type T23 = InstanceType<string>;  // Error
type T24 = InstanceType<Function>;  // Error
1
2
3
4
5
6
7
8
9
10
11

源码:

type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
// abstract 关键字 定义为抽象类 后面必须跟 class 或 new 关键字
// new 关键字 字面量构造器签名 可以理解为 interface 它描述了构造函数的形状
1
2
3

# ConstructorParameters<T> -获取构造函数参数

注意:是构造函数,即构造器中的入参,而非类对象。

class People {
  name: string
  age: number

  constructor(name: string) {
    this.name = name;
  }
}


type IType = ConstructorParameters<typeof People>
// type IType = [name: string]
1
2
3
4
5
6
7
8
9
10
11
12

源码:

type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
1
编辑 (opens new window)
上次更新: 2023/7/11 18:57:41
Partial详解
声明合并

← Partial详解 声明合并→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式