像专家一样使用TypeScript条件类型

图片

掌握TypeScript的条件类型,了解TypeScript内置的实用类型是如何工作的。

您是否使用过Exclude、Extract、NonNullable、Parameters和ReturnType实用程序类型? 你知道他们内部是怎么运作的吗? 事实上,上述TypeScript内置的实用程序类型都是基于条件类型开发的。

图片

注意:只演示过程的一部分

在这里,我们首先简要了解这些TypeScript内置实用程序类型的具体实现。

图片

这些实用程序类型用于以下目的:

  • Exclude:通过从 UnionType 中排除可赋值给 ExcludedMembers 的所有联合成员来构造类型。

  • Extract:通过从 Type 中提取可赋值给 Union 的所有联合成员来构造类型。

  • NonNullable:通过从 Type 中排除 null 和 undefined 来构造一个类型。

  • 形参:从函数类型 Type 的形参中使用的类型构造一个元组类型。

  • ReturnType:构造一个由函数 Type 返回类型组成的类型。


下面我们来看几个用法示例:

图片

如果您想彻底掌握它们并创建自己的实用程序类型,那么不要错过本文所涵盖的内容。

前面描述的内置实用程序类型在内部使用了TypeScript 2.8中引入的条件类型。该类型的语法如下:

T extends U ? X : Y

T、U、X和Y都是类型占位符。您可以这样理解语法:当类型T可以分配给类型U时,则返回类型X,否则返回类型y。看到这里,您会想起JavaScript中的三元表达式。

图片

那么条件类型有什么用呢?让我们举个例子。

type IsString<T> = T extends string ? true : false;
type I0 = IsString<number>;  // falsetype I1 = IsString<"abc">;  // truetype I2 = IsString<any>;  // booleantype I3 = IsString<never>;  // never

图片

在上面的代码中,我们定义了IsString实用程序类型。使用此实用程序类型,我们可以确定传递给类型参数T的实际类型是否为字符串类型。除了使用条件类型和条件链确定单个类型外,我们还可以同时确定多个类型。

接下来,让我们看看如何实现这个实用程序类型:

图片

在上面的代码中,我们定义了一个新的TypeName实用程序类型,并在其中使用条件链。为了使您更容易理解条件链,让我们以JavaScript三元表达式为例来演示它的作用。

图片

现在问题来了,对于前面定义的TypeName实用程序类型,如果传入的类型是联合类型,将返回什么结果? 让我们验证以下内容。​​​​​​​

// "string" | "function"type T10 = TypeName<string | (() => void)>;​​​​​​
// "string" | "object" | "undefined"type T11 = TypeName<string | string[] | undefined>;

图片

为什么T10和T11类型返回联合类型? 这是因为TypeName是一个分布式条件类型。在条件类型中,如果被检查的类型是一个“裸”类型参数,即没有被Array、Tuple、Promise等包装,则该条件类型称为分布式条件类型。

图片

对于分布式条件类型,当传入的检查类型为联合类型时,在操作过程中会将其分解为多个分支。

T extends U ? X : Y
T => A | B | C
A | B | C extends U ? X : Y  =>
(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

图片

为了让您更容易理解,让我们举一个例子。

图片

从上面的结果可以看出,如果将类型参数T包装在条件类型中,则该条件类型不是分布式条件类型,因此在操作过程中不会将其分解为分支。

在学习了条件类型和分布式条件类型之后,让我们举一个例子来演示TypeScript内置实用程序类型Exclude的执行流程。

type Exclude<T, U> = T extends U ? never : T;
​​​​​​​
type T4 = Exclude<"a" | "b" | "c", "a" | "b">
("a" extends "a" | "b" ? never : "a") // => never| ("b" extends "a" | "b" ? never : "b") // => never| ("c" extends "a" | "b" ? never : "c") // => "c"
never | never | "c" // => "c"

图片

一旦掌握了条件类型,就可以通过将它们与前几篇文章中介绍的映射类型相结合来实现一些有用的实用程序类型。

例如,实现诸如 
FunctionProperties 和 NonFunctionProperties 这样的实用程序类型。

图片

图片

type FunctionPropertyNames<T> = {    [K in keyof T]: T[K] extends Function ? K : never;}[keyof T];type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;
type NonFunctionPropertyNames<T> = {    [K in keyof T]: T[K] extends Function ? never : K;}[keyof T];type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
interface User {    id: number;    name: string;    age: number;    updateName(newName: string): void;}
type T5 = FunctionPropertyNames<User>; // "updateName"type T6 = FunctionProperties<User>; // { updateName: (newName: string) => void; }type T7 = NonFunctionPropertyNames<User>; // "id" | "name" | "age"type T8 = NonFunctionProperties<User>; // { id: number; name: string; age: number; }

在上面的代码中,使用上面的实用程序类型,我们可以很容易地在User对象类型中提取函数类型和非函数类型属性以及相关的对象类型。

读完这篇文章,我相信你已经理解了条件类型和分布式条件类型的作用,也知道了一些实用程序类型是如何在TypeScript中实现的。关于如何在条件类型中使用infer来实现类型推断,我们将在后续文章中介绍。

 欢迎关注公众号:文本魔术,了解更多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/338759.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

爬虫网易易盾滑块及轨迹算法案例:某乎

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 一、滑块初步分析 js运行 atob(‘aHR0cHM6Ly93d3cuemhpaHUuY29tL3NpZ25pbg’) 拿到网址&#xff0c;浏览器打开网站&#xff0…

IP风险画像:源头防范网络攻击的全面策略

在当今数字化的时代&#xff0c;网络攻击呈现多样化和复杂化的趋势&#xff0c;为了确保网络的安全&#xff0c;制定全面的IP风险画像并从源头防范网络攻击是至关重要的。ip数据云将探讨如何通过建立IP风险画像来识别和应对潜在的威胁&#xff0c;从而实现更加安全可靠的网络环…

系统存储架构升级分享

一、业务背景 系统业务功能&#xff1a;系统内部进行数据处理及整合, 对外部系统提供结果数据的初始化(写)及查询数据结果服务。 系统网络架构: • 部署架构对切量上线的影响 - 内部管理系统上线对其他系统的读业务无影响 •分布式缓存可进行单独扩容, 与存储及查询功能升级…

使用numpy处理图片——滤镜

大纲 3维数组切分打平重组法深度切分法 3维数组堆叠 我们在用手机拍照片时&#xff0c;往往会对照片进行滤镜处理&#xff0c;从而让照片更加美观。本文我们将实现几种滤镜效果——去除所有像素中的某一种原色&#xff0c;形成只有红绿、红蓝和绿蓝原色的照片。 为了突出色彩丰…

[算法与数据结构][c++]:Static关键字和全局变量

Static关键字和全局变量 1. 生命周期、作用域和初始化时机2. 全局变量3. Static 关键字3.1 面向过程3.1.1 静态全局变量3.1.2 静态局部变量&#xff08;单例中会使用&#xff09;3.1.3 静态函数 3.2 面向对象3.2.1 类内静态成员变量3.2.2 类内静态成员函数 Reference 写在前面&…

Leetcode2980. 检查按位或是否存在尾随零

Every day a Leetcode 题目来源&#xff1a;2980. 检查按位或是否存在尾随零 解法1&#xff1a;遍历 给你一个 正整数数组 nums 。 你需要检查是否可以从数组中选出两个或更多元素&#xff0c;满足这些元素的按位或运算&#xff08; OR&#xff09;结果的二进制表示中至少存…

如何给AVR16芯片解锁

AVRM16核心板本身集成了强大的芯片自解锁功能模块&#xff0c;当由于熔丝位设置错误&#xff0c;导致芯片锁死&#xff0c;无法正常使用时候&#xff0c;可以利用畅学AVR16核心板上的解锁功能给芯片解锁。 &#xff08;如果芯片没有锁死&#xff0c;可以跳过此步骤&#xff09…

鸿蒙Harmony--状态管理器--@Prop详解

纵横千里独行客&#xff0c;何惧前路雨潇潇。夜半浊酒慰寂寞&#xff0c;天明走马入红尘。且将新火试新茶&#xff0c;诗酒趁年华。青春以末&#xff0c;壮志照旧&#xff0c;生活以悟&#xff0c;前路未明。时间善变&#xff0c;可执着翻不了篇。时光磨我少年心&#xff0c;却…

STM32蓝牙小车、红外循迹小车、超声波避障小车项目设计

一、前言 本文旨在分享我学习STM32的过程中&#xff0c;为了强化学习成果&#xff0c;试着制作一些实训项目。最开始做的就是STM32蓝牙小车、STM32红外循迹小车、STM32超声波避障小车。 相信看完本文的你&#xff0c;一定可以亲手制作一辆属于自己的智能小车&#xff01; 注&am…

压缩编码之变换的选择之离散余弦变换(DCT)和离散傅立叶变换(DFT)——数字图像处理

原理 变换的选择是一个关键的考量因素&#xff0c;它决定了数据是如何被压缩的。选择变换时考虑以下几个重要原则&#xff1a; 数据去关联性&#xff1a;变换的目的之一是减少数据中的相关性。例如&#xff0c;在图像压缩中&#xff0c;像素间往往高度相关。通过适当的变换&a…

动手学深度学习二:关于熵和损失函数的理解

李沐动手学深度学习 课程网址&#xff1a;https://courses.d2l.ai/zh-v2/ 包含教材和视频网址链接 关于熵&#xff0c;教材中的描述非常形象&#xff0c;那就是描述信息量多少。当我们根据一些数据去预测一个结果&#xff0c;如果这些数据都单一的指向结果&#xff0c;那么这些…

Django的数据库模型的CharField字段的max_length参数与中文字符数的关系探索(参数max_length的单位是字符个数还是字节数?)

01-清理干净之前的数据库迁移信息 02-根据setting.py中的信息删除掉之前建立的数据库 03-删除之后重新创建数据库 04-models.py中创建数据库模型 from django.db import modelsclass User(models.Model):username models.CharField(max_length4)email models.EmailField(uni…