【TypeScript】高级类型

文章目录

  • 1、交叉类型
  • 2、联合类型
  • 3、类型保护
    • 3.1 用户自定义的类型保护
    • 3.2 typeof 类型保护
    • 3.3 instanceof类型保护
  • 4、类型别名
    • 4.1 定义
    • - 接口 vs. 类型别名
  • 5、可辨识联合
  • 6、索引类型
    • 6.1 类型操作符:
      • - 索引类型查询操作符:keyof T
      • - 索引访问操作符:T[K]
    • 6.2 使用索引类型
  • 7、映射类型
    • in 操作符
    • 7.1 Partial 可选
      • 使用
      • 原理
    • 7.2 Readonly 只读
      • 使用
      • 原理
    • 7.3 Pick 抽取子集
      • 使用
      • 原理
    • 7.4 Record
      • 基本语法
      • 原理
    • 7.5 有条件的映射类型
      • 7.5.1 Exclude
      • 7.5.2 Extract
      • 7.5.3 NonNullable
      • 7.5.3 ReturnType
      • 7.5.3 InstanceType

1、交叉类型

交叉类型是将多个类型合并为一个类型
交叉类型通常用于类型扩展,确保一个类型同时具有多个类型的特性
交叉类型使用 & 符号来定义

语法:

T1 & T2 & ... & Tn

示例:

interface A {a: string;
}interface B {b: number;
}type C = A & B;const c: C = {a: 'hello',b: 42,
};

2、联合类型

联合类型表示一个值可以是几种类型之一
联合类型通常用于类型保护,确保一个类型属于多个类型中的一个
联合类型使用 | 符号来定义

语法:

T1 | T2 | ... | Tn

示例:

type Options = 'A' | 'B' | 'C';const option: Options = 'A';

3、类型保护

类型保护允许你在代码块中确保变量属于某个特定的类型

3.1 用户自定义的类型保护

定义:

function isFish(pet: Fish | Bird): pet is Fish {return (<Fish>pet).swim !== undefined;
}

使用:

// 'swim' 和 'fly' 调用都没有问题了
if (isFish(pet)) {pet.swim();
}
else {pet.fly();
}

3.2 typeof 类型保护

function getLength(arg: number| string): number {if (typeof arg === 'string') {return arg.length;} else {return arg.toString().length;}
}

3.3 instanceof类型保护

const curDate = new Date();
if (curDate instanceof Date) {console.log(curDate.getHours());
}

4、类型别名

4.1 定义

类型别名会给一个类型起个新名字。
类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型
起别名不会新建一个类型 - 它创建了一个新 名字来引用那个类型
关键字:type

示例:

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name {if (typeof n === 'string') {return n;} else {return n();}
}
getName('ts')
getName(() => 'ts');
// getName(() => 123); // 报错

同接口一样,类型别名也可以是泛型 - 我们可以添加类型参数并且在别名声明的右侧传入:

type Container<T> = { value: T };

- 接口 vs. 类型别名

相同点:
1、都可以定义对象

interface Personi {name: string;age: number;
}type Persont = {name: string;age: number;
}

2、都可以定义函数

interface addTypei {(num1: number, num2: number): number;
}type addTypet = (num1: number, num2: number) => number;

不同点:
1、interface 使用 extends 实现继承, type 使用交叉类型实现继承
interface 继承 interface:

interface Person {name: string;
}
interface Student extends Person {grade: number;
}

type 继承 type:

type Person = {name: string;
}
type Student = Person & { grade: number }  // 用交叉类型

interface 继承 type:

type Person = {name: string;
}
interface Student extends Person {grade: number;
}

type 继承 interface:

interface Person {name: string;
}
type Student = Person & { grade: number }  // 用交叉类型

2、interface可以合并重复声明,type 不行(重复声明 type ,就报错了)

interface Person {name: string;
}
interface Person {age: number;
}const person: Person = {name: 'ts',age: 12,
}

3、应用场景:
一般使用组合或者交叉类型的时候,用 type
一般要用类的 extendsimplements 时,用 interface

5、可辨识联合

你可以合并单例类型,联合类型,类型保护和类型别名来创建一个叫做可辨识联合的高级模式,它也称做标签联合代数数据类型
分3步骤:

  1. 具有普通的单例类型属性— 可辨识的特征。
  2. 一个类型别名包含了那些类型的联合— 联合。
  3. 此属性上的类型保护。

示例:
步骤1:

interface Square {kind: "square";size: number;
}
interface Rectangle {kind: "rectangle";width: number;height: number;
}
interface Circle {kind: "circle";radius: number;
}

步骤2:

type Shape = Square | Rectangle | Circle;

步骤3:

function area(s: Shape) {switch (s.kind) {case "square": return s.size * s.size;case "rectangle": return s.height * s.width;case "circle": return Math.PI * s.radius ** 2;}
}

完整性检查
当没有涵盖所有可辨识联合的变化时,我们想让编译器可以通知我们。 比如,如果我们添加了 Triangle到 Shape,我们同时还需要更新 area:

type Shape = Square | Rectangle | Circle | Triangle;
function area(s: Shape) {switch (s.kind) {case "square": return s.size * s.size;case "rectangle": return s.height * s.width;case "circle": return Math.PI * s.radius ** 2;}// should error here - we didn't handle case "triangle"
}

解决办法:
使用 never类型,编译器用它来进行完整性检查:

function assertNever(x: never): never {throw new Error("Unexpected object: " + x);
}
function area(s: Shape) {switch (s.kind) {case "square": return s.size * s.size;case "rectangle": return s.height * s.width;case "circle": return Math.PI * s.radius ** 2;default: return assertNever(s); // error here if there are missing cases}
}

6、索引类型

使用索引类型,编译器就能够检查使用了动态属性名的代码

6.1 类型操作符:

先介绍两种新的类型操作符:

- 索引类型查询操作符:keyof T

keyof 操作符可以用于获取某种类型的所有键
其返回类型是联合类型
比如:

interface Person {name: string;age: number;
}let personProps: keyof Person; // 'name' | 'age'

- 索引访问操作符:T[K]

T[K],表示接口 T 的属性 K 所代表的类型
示例:

interface IPerson {name: string;age: number;
}let type1:  IPerson['name'] = 'hello' // string
let type2:  IPerson['age'] = 23 // numberconsole.log(type1) // hello
console.log(type2) // 23

6.2 使用索引类型

索引类型查询操作符 (keyof T) 和索引访问操作符 (T[K]), 你可以在泛型约束中使用它们来访问另一个类型的属性的类型
示例1:

function getProperty<T, K extends keyof T>(obj: T, key: K) {return obj[key]; // T[K] 类型的返回值
}let obj = {name: 'hello',age: 23,
}
getProperty(obj, 'name'); // 正确
getProperty(obj, 'grade'); // 错误,grade 不在 obj 中

示例2:
传入key的数组,获取对应的值的数组

function getValues<T, K extends keyof T>(userInfo: T, keys: K[]): T[K][] {return keys.map(key => userInfo[key]);
}const userInfo = {name: 'ts',age: 12,
}
getValues(userInfo, ['name', 'age'])
// getValues(userInfo, ['sex', 'age']) // 这样当我们指定不在对象里的属性时,就会报错

7、映射类型

在 TypeScript 中是一种基于现有类型生成新类型的方式,它通过一个已知的类型,映射出一个新的类型
映射类型的基本形式使用一个 for…in 这样的循环语法,遍历某个类型的属性键,在映射过程中,你可以为这些属性应用修饰符或其他类型转换

in 操作符

用来对联合类型实现遍历

type Person = "name" | "school" | "major";
type obj = {[p in Person]: string;
}

7.1 Partial 可选

使用

Partial<T>T的所有属性映射为可选的
示例:

interface Person {name: string;age: number;
}type PersonPartial = Partial<Person>;// 使用 Partial 改造一下,就可以变成可选属性
let P1: PersonPartial = {}; 

原理

type MyPartial<T> = {[P in keyof T]?: T[P];
} 

7.2 Readonly 只读

使用

Readonly<T>T的所有属性映射为只读的
示例:

interface Person {name: string;age: number;
}type PersonReadonly = Readonly<Person>;let p1: PersonReadonly = {name: 'hello',age: 12
}; 
// p1.name = 'world' // 报错

原理

type MyReadonly<T> = {readonly [P in keyof T]: T[P];
}

7.3 Pick 抽取子集

Pick用于抽取对象子集,挑选一组属性并组成一个新的类型

使用

interface Person {name: string;age: number;sex: string;
}type PersonPick = Pick<Person, 'name' | 'age'>;let p1: PersonPick = {name: 'hello',age: 12
}; 

原理

type MyPick<T, K extends keyof T> = {[P in K]: T[P]
}

7.4 Record

用于创建一个对象类型,其属性键为 Keys,属性值类型为 Type
这使得我们能快速的构造一个具有固定类型值的对象,而键的部分则来自于一个联合类型或字面量类型

基本语法

Record<Keys, Type>
  • Keys 是一个字符串(或数字)字面量的联合类型,表示可枚举的键。
  • Type 是任何有效的 TypeScript 类型,表示每个属性的值的类型。

示例1:

interface Person {name: string;age: number;
}type PersonRecord = Record<string, Person>let personMap: PersonRecord = {p1: {name: 'hello',age: 12}  
}

示例2:

type PageInfo = {title: string;
};// 字符串字面量的联合类型
type Page = 'home' | 'about' | 'contact';// Record 类型将 Page 类型的每个属性都映射到 PageInfo 类型
const nav: Record<Page, PageInfo> = {home: { title: 'Home' },about: { title: 'About' },contact: { title: 'Contact' }
};

原理

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

7.5 有条件的映射类型

使用条件类型在映射时添加逻辑

T extends U ? X : Y 
// 若类型 T 可被赋值给类型 U,那么结果类型就是 X 类型,否则就是 Y 类型
// extends在这里不是用于类继承,而是表示一个条件类型查询,即“T 是否可以赋值给 U” 

预定义的有条件类型:

7.5.1 Exclude

Exclude<T, U> – 从T中剔除可以赋值给U的类型
示例:

type T00 = Exclude<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // "b" | "d"
let t1: T00 = 'b';
let t2: T00 = 'd';
// let t3: Test = 'a'; // 报错,不包含'a'type T02 = Exclude<string | number | (() => void), Function>;  // string | number

Exclude 原理

  • never表示一个不存在的类型
  • never与其他类型的联合后,为其他类型
type Exclude<T, U> = T extends U ? never : T

示例:

type T1 = Exclude<'a' | 'b' | 'c', 'a'>;
// 类型为 'b' | 'c',因为 'a' 可以赋值给 'a',所以被排除了。type T2 = Exclude<'a' | 'b' | 'c', 'a' | 'b'>;
// 类型为 'c',因为 'a' | 'b' 都可以赋值给 'a' | 'b',所以被排除了。

7.5.2 Extract

Extract<T, U> – 提取T中可以赋值给U的类型

type T01 = Extract<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // "a" | "c"type T02 = Extract<string | number | (() => void), Function>;  // () => void

Extract 原理

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

7.5.3 NonNullable

NonNullable<T> – 从T中剔除null和`undefined

type T04 = NonNullable<string | number | undefined>;  // string | number
type T05 = NonNullable<(() => string) | string[] | null | undefined>;  // (() => string) | string[]

7.5.3 ReturnType

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

type T10 = ReturnType<() => string>;  // string
type T11 = ReturnType<(s: string) => void>;  // void
type T12 = ReturnType<(<T>() => T)>;  // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]function f1(s: string) {return { a: 1, b: s };
}
type T14 = ReturnType<typeof f1>;  // { a: number, b: string }type T15 = ReturnType<any>;  // any
type T16 = ReturnType<never>;  // any
type T17 = ReturnType<string>;  // Error
type T18 = ReturnType<Function>;  // Error

7.5.3 InstanceType

InstanceType<T> – 获取构造函数类型的实例类型

class C {x = 0;y = 0;
}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

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

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

相关文章

基于springboot的停车场管理系统-计算机毕业设计源码82061

摘要 由于数据库和数据仓库技术的快速发展&#xff0c;停车场管理系统建设越来越向模块化、智能化、自我服务和管理科学化的方向发展。停车场管理系统对处理对象和服务对象&#xff0c;自身的系统结构&#xff0c;处理能力&#xff0c;都将适应技术发展的要求发生重大的变化。停…

Kubernetes 学习总结(45)—— 懂 Pod 就懂了 Kubernetes 的一半

前言 Kubernetes 可以理解成一个对计算、网络、存储等云计算资源的抽象后的标准 API 服务。几乎所有对 Kubernetes 的操作&#xff0c;不管是用 kubectl 命令行工具&#xff0c;还是在UI或者CD Pipeline 中&#xff0c;都相当于在调用其 REST API。很多人说 Kubernetes 复杂&a…

docker nginx滚动日志配置

将所有日志打印到控制台 nginx.conf user nginx; worker_processes auto; # 日志打印控制台 error_log /dev/stdout; #error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;events {worker_connections 1024; }http {include /etc/nginx/m…

循环链表和双向链表

下面是 C 语言中循环链表和双链表的链式表示和实现示例&#xff1a; **循环链接表&#xff1a;** c #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node* next; }; // Function to create a new node struct Node* createNode(int da…

Mysql与Redis如何保证数据一致性问题

目录 一、Mysql与Redis同步数据是否存在延迟呢&#xff1f; 二、如何保证一致性&#xff1f; 2.1、第一种方式&#xff1a;手动编码 2.2、第二种方式&#xff1a;MQ异步更新 2.3、第三种方式&#xff1a;binlog同步数据 2.4、第四种方式&#xff1a;双写一致性 2.5、第五…

ASP.NET可视化流程设计器源码

源码介绍: ASP.NET可视化流程设计器源码已应用于众多大型企事业单位。拥有全浏览器兼容的可视化流程设计器、表单设计器、基于角色的权限管理等系统开发必须功能&#xff0c;大大为您节省开发时间&#xff0c;是您开发OA.CRM、HR等企事业各种应用管理系统和工作流系统的最佳基…

Python爬虫获取百度的图片

一. 爬虫的方式&#xff1a; 主要有2种方式: ①ScrapyXpath (API 静态 爬取-直接post get) ②seleniumXpath (点击 动态 爬取-模拟) ScrapyXpath XPath 是 Scrapy 中常用的一种解析器&#xff0c;可以帮助爬虫定位和提取 HTML 或 XML 文档中的数据。 Scrapy 中使用 …

Intel x86架构之I/O APIC

全文来自Intel手册&#xff08;见参考1&#xff09;&#xff1a;Intel? 82093AA I/O Advanced Programmable Interrupt Controller (I/O APIC) Datasheet 注意&#xff1a;下文中已经指出手册中的对应页面和章节&#xff0c;请对照手册原文看&#xff0c;任何个人理解错误&…

期货日数据维护与使用_日数据维护_模块整体代码

目录 写在前面 setting.py sqlite_tool.py future_widget.py 写在前面 本文默认已经创建了项目&#xff0c;如果不知道如何创建一个空项目的&#xff0c;请参看以下两篇博文 PyQt5将项目搬到一个新的虚拟环境中 https://blog.csdn.net/m0_37967652/article/details/122…

tcp和udp的区别(附java实现)

TCP和UDP的区别 TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种不同的网络传输协议&#xff0c;它们在数据传输时有一些重要的区别。 TCP TCP是面向连接的协议&#xff0c;它在通信之前需要建立连接&…

InternLM第2节课笔记

轻松玩转书生浦语大模型趣味Demo InternLM模型全链条开源 InternLM-7B和InternLM-20B Lagent&#xff1a;智能体&#xff08;agent&#xff09;框架 浦语灵笔&#xff1a;InternLM-Xcomposer-7B 视觉-语言大模型 模型下载 Hugging Face huggingface-cli OpenXLab python…

【C++】- 类和对象(!!C++类基本概念!this指针详解)

类和对象 引入类类的定义类的访问限定操作符类的作用域类的实例化类对象模型this指针 引入类 在 C中&#xff0c;引入了一个新的定义----------类。类是一种用户自定义的数据类型&#xff0c;用于封装数据和行为。类可以看作是一个模板或蓝图&#xff0c;描述了一组相关的数据和…

第15课 利用openCV实现人脸识别

这节课&#xff0c;我们再来看一个简单且实用的例子&#xff1a;人脸识别。这个小例子可以让你进一步领略openCV的强悍。 1.复制demo14并改名为demo15。 2.修改capImg函数&#xff1a; int fmle::capImg() {// 加载人脸检测分类器cv::CascadeClassifier faceCascade;faceCas…

UEditor在编辑对齐方式时产生额外空行问题

一、问题描述 一个关于UEditor富文本编辑器的问题&#xff1a;在编辑内容对齐方式后保存后浏览器显示的段落上下会比原先多出一些间距。 下面是对齐编辑后&#xff0c;未保存前的的HTML&#xff1a; 保存后&#xff0c;实际会多出一个段落空行&#xff1a; 二、问题调查 经…

基于B/S架构的数字孪生智慧监所可视化监管系统

1 前言 物联网技术的发展使云计算技术得到了迅猛的发展及广泛的应用&#xff0c;智能体系的创建已经成为监狱发展的必然趋势。 智慧监狱的创建、智能化管理的推行是监狱管理的创新&#xff0c;也是监狱整体工作水平提升的具体体现。 1.1 建设背景 近年来&#xff0c;司法部不…

CISSP 第7章:PKI和密码学应用

第七章 PKI和密码学应用 7.1 非对称密码学 对称密码系统具有共享的秘钥系统&#xff0c;从而产生了安全秘钥分发的问题 非对称密码学使用公钥和私钥对&#xff0c;无需支出复杂密码分发系统 7.1.1 公钥与私钥 7.1.2 RSA&#xff08;兼具加密和数字签名&#xff09; RSA算法依赖…

ctrl + v获取图片和文字

1、效果实现 1.1、做法 容器监听paste事件。原生js则document.addEventListener(paste)&#xff0c;vue则paste 监听paste事件的回调函数有个参数e&#xff0c;获取e.clipboardData粘贴的文字信息 e.clipboardData.getData("text/plain")粘贴的图片信息 e.clipboard…

委托QAbstractItemDelegate

参考&#xff1a;QT(7)-初识委托_qt 委托-CSDN博客 一、 1、 模型&#xff1a;负责“组织”数据&#xff1b; 视图&#xff1a;负责“显示”数据&#xff1b; 委托&#xff1a;负责“修改”数据&#xff1b; 2、委托&#xff1a;在QT的MV模型中&#xff0c;处理特定类型的…

c++拷贝控制

文章目录 拷贝构造函数的基本概念定义语法何时使用拷贝构造函数示例代码运行结果注意事项 拷贝赋值运算符的基本概念定义语法何时使用拷贝赋值运算符示例代码运行结果注意事项 析构函数的基本概念定义语法何时调用析构函数示例代码运行结果注意事项 三/五法则三法则 (Rule of T…

【SpringCloud】之配置中心(进阶使用)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《SpringCloud开发之远程消费》。&#x1f3af;&a…