Typescript基础知识(类型断言、类型别名、字符串字面量类型、枚举、交叉类型)
系列文章目录
引入一:Typescript基础引入(基础类型、元组、枚举)
引入二:Typescript面向对象引入(接口、类、多态、重写、抽象类、访问修饰符)
第一章:Typescript基础知识(Typescript介绍、搭建TypeScript环境、基本数据类型)
第二章:Typescript常用类型(任意值any、数组Array、函数Function、元组Tuple、类型推论、联合类型)
第三章:Typescript基础知识(类型断言、类型别名、字符串字面量类型、枚举、交叉类型)
文章目录
- 系列文章目录
- 一、类型断言
- 1.1 语法
- 1.2 断言的用途
- 1.2.1 将一个联合类型断言为其中一个类型
- 1.2.2 将一个父类断言为更加具体的子类
- 1.2.3 将任何一个类型断言为any
- 1.2.4 将 any 断言为一个具体的类型
- 1.3 非空断言运算符( ! 后缀)
- 1.4 确定赋值断言
- 二、类型别名
- 三、字面量类型
- 3.1 字符串字面量类型
- 3.2 数字字面量类型及布尔字面量类型
- 四、枚举
- 4.1 手动赋值
- 五、交叉类型
一、类型断言
类型断言(Type Assertion)可以用来手动指定一个值的类型。
1.1 语法
值 as 类型
或者
<类型>值
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用前者,即值 as 类型
,因此我们更推荐使用 as 语法。
形如 的语法在 tsx 中表示的是一个 ReactNode,在ts中除了表示类型断言之外,也可能是表示一个泛型。
1.2 断言的用途
1.2.1 将一个联合类型断言为其中一个类型
- 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们
只能访问此联合类型的所有类型中共有的属性或方法
。 - 当我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法时,就会报错。
interface Cat {name: string;run(): void;
}
interface Fish {name: string;swim(): void;
}function getName(animal: Cat | Fish) {return animal.name;
}function isFish(animal: Cat | Fish) {if (typeof animal.swim === 'function') {return true;}return false;
}
// index.ts:11:23 - error TS2339: Property 'swim' does not exist on type 'Cat | Fish'.
// Property 'swim' does not exist on type 'Cat'.
此时可以使用类型断言,将 animal 断言成 Fish:
interface Cat {name: string;run(): void;
}
interface Fish {name: string;swim(): void;
}function isFish(animal: Cat | Fish) {if (typeof (animal as Fish).swim === 'function') {return true;}return false;
}
1.2.2 将一个父类断言为更加具体的子类
当类之间有继承关系时,类型断言也是很常见:
class ApiError extends Error {code: number = 0;
}
class HttpError extends Error {statusCode: number = 200;
}function isApiError(error: Error) {if (typeof (error as ApiError).code === 'number') {return true;}return false;
}
上述例子中,由于父类 Error 中没有 code 属性,故直接获取 error.code 会报错,需要使用类型断言获取 (error as ApiError).code。
上述例子中有一个更合适的方式来判断是不是 ApiError,那就是使用 instanceof:
class ApiError extends Error {code: number = 0;
}
class HttpError extends Error {statusCode: number = 200;
}function isApiError(error: Error) {if (error instanceof ApiError) {return true;}return false;
}
但是当 ApiError 和 HttpError 不是一个真正的类
,而是一个 TypeScript 的接口
(interface),接口是一个类型,不是一个真正的值,它在编译结果中会被删除,就无法使用 instanceof 来做运行时判断,此时就只能用类型断言
,通过判断是否存在 code 属性,来判断传入的参数是不是 ApiErro:
interface ApiError extends Error {code: number;
}
interface HttpError extends Error {statusCode: number;
}
/*
function isApiError(error: Error) {if (error instanceof ApiError) {return true;}return false;
}// index.ts:9:26 - error TS2693: 'ApiError' only refers to a type, but is being used as a value here.
*/function isApiError(error: Error) {if (typeof (error as ApiError).code === 'number' ) {return true;}return false;
}
1.2.3 将任何一个类型断言为any
当我们需要将 window 上添加一个属性 foo,但 TypeScript 编译时会报错,提示我们 window 上不存在 foo 属性。
window.foo = 1;// index.ts:1:8 - error TS2339: Property 'foo' does not exist on type 'Window & typeof globalThis'.
此时我们可以使用 as any 临时将 window 断言为 any 类型:
(window as any).foo = 1;
注意: 将一个变量断言为 any 可以说是解决 TypeScript 中类型问题的最后一个手段。它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 as any。
1.2.4 将 any 断言为一个具体的类型
开发中,我们不可避免的需要处理 any 类型的变量,遇到 any 类型的变量时,我们可以选择无视它,任由它滋生更多的 any。
我们也可以选择改进它,通过类型断言及时的把 any 断言为精确的类型
:
function getCacheData(key: string): any {return (window as any).cache[key];
}interface Cat {name: string;run(): void;
}const tom = getCacheData('tom') as Cat;
tom.run();
1.3 非空断言运算符( ! 后缀)
在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。 !
在任何表达式之后写入
代表一种类型断言,即该值不是 null or undefined
:
let mayNullOrUndefinedOrString: null | undefined | string;
mayNullOrUndefinedOrString!.toString(); // ok
mayNullOrUndefinedOrString.toString(); // error
function liveDangerously(x?: number | null) { console.log(x!.toFixed());
}
1.4 确定赋值断言
允许在实例属性和变量声明后面放置一个 ! 号
,从而告诉 TypeScript 该属性会被明确地赋值
。
let x: number;
initialize();console.log(2 * x); // Variable 'x' is used before being assigned.(2454)
function initialize() {x = 10;
}
上述例子中,该异常信息是说变量 x 在赋值前被使用了,要解决该问题,我们可以使用确定赋值断言
let x!: number;
initialize();console.log(2 * x);
function initialize() {x = 10;
}
二、类型别名
类型别名用来给一个类型起个新名字
(类型别名常用于联合类型)
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {if (typeof n === "string") {return n;} else {return n();}
}function test() {return "hello";
}
console.log(getName("zs"));//zs
console.log(getName(test));//hello
三、字面量类型
3.1 字符串字面量类型
字符串字面量类型用来约束取值只能是某几个字符串中的一个。
type Direction = 'up' | 'down';function move(dir: Direction) {console.log(dir)
}
move('up'); // up
move('right'); // error:Argument of type '"right"' is not assignable to parameter of type 'Direction'
相较于使用 string 类型,使用字面量类型可以将函数的参数限定为更具体的类型
。这不仅提升了程序的可读性,还保证了函数的参数类型,可谓一举两得。
3.2 数字字面量类型及布尔字面量类型
数字字面量类型和布尔字面量类型的使用与字符串字面量类型的使用类似,我们可以使用字面量组合的联合类型将函数的参数限定为更具体的类型:
interface Config {size: 'small' | 'big';isEnable: true | false;margin: 0 | 2 | 4;
}let conf: Config = {size: "big",isEnable: true,margin: 1,//error: Type '1' is not assignable to type '0 | 2 | 4'
};
四、枚举
枚举(Enum)类型用于取值被限定在一定范围内的场景.枚举使用 enum
关键字来定义。
枚举成员会被赋值为从 0 开始递增的数字
,同时也会对枚举值到枚举名进行反向映射
。
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};console.log(Days);
/*
{'0': 'Mon','1': 'Tue','2': 'Wed','3': 'The','4': 'Fri','5': 'Sat',Sun: 'text',Mon: 0,Tue: 1,Wed: 2,The: 3,Fri: 4,Sat: 5
}
*/
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // trueconsole.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true
var Days;
(function (Days) {Days[Days["Sun"] = 0] = "Sun";Days[Days["Mon"] = 1] = "Mon";Days[Days["Tue"] = 2] = "Tue";Days[Days["Wed"] = 3] = "Wed";Days[Days["The"] = 4] = "The";Days[Days["Fri"] = 5] = "Fri";Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));
console.log(Days);
console.log(Days.Sun);
console.log(Days["Mon"]);
console.log(Days["The"]);
console.log(Days[0]);
console.log(Days[1]);
console.log(Days[4]);
4.1 手动赋值
我们也可以给枚举项手动赋值,未手动赋值的枚举项会接着上一个枚举项递增
。如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的:
enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
上面的例子中,递增到 3 的时候与前面的 Sun 的取值重复了,但是 TypeScript 并没有报错,导致 Days[3] 的值先是 “Sun”,而后又被 “Wed” 覆盖了。编译的结果是:
var Days;
(function (Days) {Days[Days["Sun"] = 3] = "Sun";Days[Days["Mon"] = 1] = "Mon";Days[Days["Tue"] = 2] = "Tue";Days[Days["Wed"] = 3] = "Wed";Days[Days["Thu"] = 4] = "Thu";Days[Days["Fri"] = 5] = "Fri";Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));
所以使用的时候需要注意,最好不要出现这种覆盖的情况。
手动赋值的枚举项可以不是数字,可以是其他类型:
enum Color {Red,Green,Blue = "blur",
}
console.log(Color); //{ '0': 'Red', '1': 'Green', Red: 0, Green: 1, Blue: 'blur' }
五、交叉类型
交叉类型是将多个类型合并为一个类型
。它包含了所需的所有类型的特性,使用&定义交叉类型
。
{type Useless = string & number;
}
如果我们仅仅把原始类型、字面量类型、函数类型等原子类型合并成交叉类型,是没有任何意义的。在上述的代码中,类型别名 Useless 的类型就是个 never。
交叉类型真正的用处是将多个接口类型合并成一个类型,从而实现等同接口继承的效果
,也就是所谓的合并接口类型,如下代码所示:
type IntersectionType = { id: number; name: string; } & { age: number };
const mixed: IntersectionType = {id: 1,name: 'name',age: 18}
在上述示例中,我们通过交叉类型,使得 IntersectionType 同时拥有了 id、name、age 所有属性,这里我们可以试着将合并接口类型理解为求并集。
相关文章:
Typescript基础知识(类型断言、类型别名、字符串字面量类型、枚举、交叉类型)
系列文章目录 引入一:Typescript基础引入(基础类型、元组、枚举) 引入二:Typescript面向对象引入(接口、类、多态、重写、抽象类、访问修饰符) 第一章:Typescript基础知识(Typescri…...

Windows系统扩充C盘空间系列方法总结
目录前言方法一 使用自带的Windows的DiskPart扩充C盘1. 打开cmd2.三步命令方法二:使用Windows系统内置磁盘管理扩展C盘方法三. 使用专业磁盘分区工具总结前言 本教程是总结Windows系统进行C盘(系统盘)扩充空间的系列方法,一般来讲…...
华为OD机试 - 跳格子(Python)
跳格子 题目 地上共有N个格子,你需要跳完地上所有的格子, 但是格子间是有强依赖关系的,跳完前一个格子后, 后续的格子才会被开启,格子间的依赖关系由多组steps数组给出, steps[0]表示前一个格子,steps[1]表示steps[0]可以开启的格子: 比如[0,1]表示从跳完第0个格子以后…...
Java配置文件的值注入
1.平常使用直接在变量头上加上Value就可以把配置文件的值注入进来 Value(“${environment.active}”) private String environment; 2.但是变量使用static修饰时,就不能注入进来了 Value(“${environment.active}”) private static String environment; 这是因…...
SAP 订单BOM与销售BOM的区别
订单BOM与销售BOM的区别 訂單BOM: 是實際生產時用的BOM, 在標準BOM和銷售BOM基礎上增減物料的BOM 銷售BOM: 是為特定客戶設定的BOM, 在主檔數據層次上的BOM, 在生產時是帶到訂單BOM中去的. 標準BOM: 是公司為標準生產的BOM, 在主檔數據層次上的BOM, 在生產時是帶到訂單BOM中去的…...

支付宝支付详细流程
1、二维码的生成二维码生成坐标 <!-- zxing生成二维码 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version></dependency><dependency><groupId>co…...

TCP 的演化史-fast retransmit/recovery
工作原因要对一个 newreno 实现增加 sack 支持。尝试写了 3 天 C,同时一遍又一遍梳理 sack 标准演进。这些东西我早就了解,但涉及落地写实现,就得不断抠细节,试图写一个完备的实现。 这事有更简单的方法。根本没必要完全实现 RFC…...

CSS基础选择器,你认识多少?
前言在上一文初识CSS中,我们了解到了其格式:选择器{ }在初步尝试使用时,我们笼统的直接输入了p { }以选择p标签来对其操作,而这一章节里,我们再进一步探索有关基础选择器的相关内容,理解选择器的作用。选择…...

ChatGPT入门案例|商务智能对话客服(三)
本篇介绍智能客服的基本功能架构和基本概念,并利用对话流技术构建商务智能应用。 01、商务智能客服功能结构 互联网的发展已经深入到社会的各个方面,智能化发展已经成为社会发展的大趋势。在大数据和互联网时代,企业和组织愈加重视客户沟通…...

Matlab 最小二乘法拟合平面(SVD)
文章目录 一、简介1.1最小二乘法拟合平面1.2 SVD角度二、实现代码三、实现效果参考资料一、简介 1.1最小二乘法拟合平面 之前我们使用过最为经典的方式对平面进行了最小二乘拟合(点云最小二乘法拟合平面),其推导过程如下所示: 仔细观察一下可以发现...
AtCoder Regular Contest 126 D题题解
思路 首先我们看看假设选中 mmm 个数后的答案。 我们首先现将 mmm 个数移动到一起,在将他们重新排序。 我们知道,mmm 个数移在一起时,当位于中间的那个数不动时交换次数最少,于是可以列出式子(cic_ici 是点 iii 的…...
Android R WiFi热点流程浅析
Android R WiFi热点流程浅析 Android上的WiFi SoftAp功能是用户常用的功能之一,它能让我们分享手机的网络给其他设备使用。 那Android系统是如何实现SoftAp的呢,这里在FWK层面做一个简要的流程分析,供自己记录和大家参考。 以Android R版本为…...

【C++进阶】二、多态详解(总)
目录 一、多态的概念 二、多态的定义及实现 2.1 多态的构成条件 2.2 虚函数 2.3 虚函数的重写 2.4 虚函数重写的两个例外 2.4.1 协变 2.4.2 析构函数的重写 2.5 C11 override 和 final 2.5.1 final 2.5.2 override 2.6 重载、覆盖(重写)、隐藏(重定义)的对比 三、…...

node-sass@4.14.1 包含风险, 如何升级依赖至 dart-sass
文章目录需求我上网都查到了哪些信息在 github 看到了 node-sass 依赖的最新版本的列表:关于方案2的失败不同版本的 nodejs 和 node-sass依赖的**适配关系**从何得知替代方案——dart-sass如何安装 dart sass?需求 在做一个基于Node、React的前端项目&a…...

DataWhale 大数据处理技术组队学习task2
三、Hadoop分布式文件系统 1. 产生背景 数据量越来越大,一台独立的计算机已经无法存储所有的数据---->将大规模的数据存储到成百上千的计算机中------为了解决数据管理以及维护极其繁琐与低效------>分布式文件系统 分布式文件系统是管理网络中跨多台计算机…...

一文读懂select、poll、epoll的用法
select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,…...

《C陷阱与缺陷》----词法“陷阱”
导言: 由于一个程序错误可以从不同层面采用不同方式进行考察,而根据程序错误与考察程序的方式之间的相关性,可以将程序错误进行划分为各种陷阱与缺陷: ①.词法“陷阱” ②.语法“陷阱” ③.语义“陷阱” ④.连接问题 ⑤.库函数问…...

千锋教育+计算机四级网络-计算机网络学习-04
UDP概述 UDP协议 面向无连接的用户数据报协议,在传输数据前不需要先建立连接;目地主机的运输层收到UDP报文后,不需要给出任何确认 UDP特点 相比TCP速度稍快些简单的请求/应答应用程序可以使用UDP对于海量数据传输不应该使用UDP广播和多播应用…...
蓝桥杯算法训练合集十四 1.P08052.P07053.同余方程4.P08015.ascii应用
目录 1.P0805 2.P0705 3.同余方程 4.P0801 5.ascii应用 1.P0805 问题描述 当两个比较大的整数相乘时,可能会出现数据溢出的情形。为避免溢出,可以采用字符串的方法来实现两个大数之间的乘法。具体来说,首先以字符串的形式输入两个整数&…...

判断字符串中的字符的类型isdecimal();isalpha();isdigit();isalnum()
【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 判断字符串中的字符的类型 isdecimal();isalpha();isdigit();isalnum() [太阳]选择题 对于代码中isdecimal()和isalnum()输出的结果是? s "ABc123&…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...