当前位置: 首页 > news >正文

TypeScript 非空断言

TypeScript 非空断言

发布于 2020-04-08 15:20:15

17.5K0

举报

一、非空断言有啥用

介绍非空断言前,先来看个示例:

function sayHello(name: string | undefined) {let sname: string = name; // Error
}

对于以上代码,TypeScript 编译器会提示一下错误信息:

Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.

要解决上述问题,我们可以简单加个条件判断:

function sayHello(name: string | undefined) {let sname: string;if (name) {sname = name;}
}

使用这种方案,问题是解决了。但有没有更简单的方式呢?答案是有的,就是使用 TypeScript 2.0 提供的非空断言操作符:

function sayHello(name: string | undefined) {let sname: string = name!;
}

二、非空断言操作符简介

在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非undefined 类型。具体而言,x! 将从 x 值域中排除 nullundefined

下面我们来介绍一下非空断言操作符的一些使用场景和注意事项。

2.1 忽略 undefined 和 null 类型

function myFunc(maybeString: string | undefined | null) {// Type 'string | null | undefined' is not assignable to type 'string'.// Type 'undefined' is not assignable to type 'string'. const onlyString: string = maybeString; // Errorconst ignoreUndefinedAndNull: string = maybeString!; // Ok
}

2.2 调用函数时忽略 undefined 类型

type NumGenerator = () => number;function myFunc(numGenerator: NumGenerator | undefined) {// Object is possibly 'undefined'. // Cannot invoke an object which is possibly 'undefined'.const num1 = numGenerator(); // Errorconst num2 = numGenerator!(); //OK
}

2.3 使用非空断言操作符的注意事项

因为 ! 非空断言操作符会从编译生成的 JavaScript 代码中移除,所以在实际使用的过程中,要特别注意。

下面我们来举两个简单的示例:

示例一

const a: number | undefined = undefined;
const b: number = a!;
console.log(b);

以上 TS 代码会编译生成以下 ES5 代码:

"use strict";
const a = undefined;
const b = a;
console.log(b);

虽然在 TS 代码中,我们使用了非空断言,使得 const b: number = a!; 语句可以通过 TypeScript 类型检查器的检查。但在生成的 ES5 代码中,! 非空断言操作符被移除了,所以在浏览器中执行以上代码,在控制台会输出 undefined

示例二

type NumGenerator = () => number;function myFunc(numGenerator: NumGenerator | undefined) {const num1 = numGenerator!();
}// Uncaught TypeError: numGenerator is not a function
myFunc(undefined); // Error

以上 TS 代码会编译生成以下 ES5 代码:

"use strict";
function myFunc(numGenerator) {var num1 = numGenerator();
}// Uncaught TypeError: numGenerator is not a function
myFunc(undefined); // Error

若在浏览器中运行以上代码,在控制台会输出以下错误信息:

Uncaught TypeError: numGenerator is not a functionat myFunc (eval at <anonymous> (main-3.js:1239), <anonymous>:3:16)at eval (eval at <anonymous> (main-3.js:1239), <anonymous>:6:1)at main-3.js:1239

很明显在运行时,undefined 并不是函数对象,所以就不能正常调用。

需要注意的是,非空断言操作符仅在启用 strictNullChecks 标志的时候才生效。当关闭该标志时,编译器不会检查 undefined 类型和 null 类型的赋值。

三、非空断言操作符使用示例

在以下示例中,首先我们使用 TypeScript 类型别名定义了一个 ListNode 类型,用于表示链表节点。该类型包含 datanext 两个属性,分别表示当前节点的值和下个节点。之后,我们还定义了以下两个函数:

  • addNext(node: ListNode):用于添加下一个节点;
  • setNextValue(node: ListNode, value: number):用于设置下一个节点的值。
type ListNode = { data: number; next?: ListNode; };function addNext(node: ListNode) {if (node.next === undefined) {node.next = {data: 0};}
}function setNextValue(node: ListNode, value: number) {addNext(node);// (property) next?: ListNode | undefined// Object is possibly 'undefined'.(2532)node.next.data = value; // Error
}

对于以上代码尽管我们知道在调用 addNext 方法后,node.next 属性会被定义,但 TypeScript 在 node.next.data = value 这行代码中并不能推断出这些。这时候我们可以使用非空断言运算符 ! 来断言 node.next 并不是 undefined,并且使编译器警告无效:

function setNextValue(node: ListNode, value: number) {addNext(node);node.next!.data = value;
}

接着我们继续看一个示例,假设你有一个表示 AJAX 请求过程的 UI 状态。它要么处于初始状态(initial),要么处于挂起状态(pending),要么处于完成状态(complete),要么处于错误状态(error)。只有在完成状态下才有响应,否则为 null。

type AjaxState<T> = {state: 'initial' | 'pending' | 'complete' | 'error';response: T | null;
}function getAjaxState( ajaxState: AjaxState<number[]> ) {if (ajaxState.state === 'complete') {// (property) response: number[] | null// Object is possibly 'null'.(2531)console.log(ajaxState.response.length); // Error}
}

虽然我们知道当请求的状态为 complete 时,响应对象不会为 null,但 TypeScript 并无法感知这些,所以我们还需要使用非空断言 ajaxState.response!.length 来忽略空值并使编译器警告无效。对于这种场景,其实有一个更好的解决方案,即使用可辨识联合:

type AjaxState<T> = { state: 'initial'|'pending'|'error', response: null } |{ state: 'complete', response: T };function getAjaxState( ajaxState: AjaxState<number[]> ) {if (ajaxState.state === 'complete') {console.log(ajaxState.response.length);}
}

通过引入可辨识联合类型,我们把为 null 和非 null 的响应完美的区分开来,还避免了再次使用非空断言,此外还大大提高了程序的可读性。在 TypeScript 实际项目的开发过程中,除了使用非空断言(!)之外,读者还可以使用 TypeScript 3.7 版本中新引入的可选链运算符(?.)和空值合并运算符(??)来提高程序的可读性。

相关文章:

TypeScript 非空断言

TypeScript 非空断言 发布于 2020-04-08 15:20:15 17.5K0 举报 一、非空断言有啥用 介绍非空断言前&#xff0c;先来看个示例&#xff1a; function sayHello(name: string | undefined) {let sname: string name; // Error } 对于以上代码&#xff0c;TypeScript 编译器…...

Python编程——谈谈函数的定义、调用与传入参数

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 本文专栏&#xff1a;Python专栏 专栏介绍&#xff1a;本专栏为免费专栏&#xff0c;并且会持续更新python基础知识&#xff0c;欢迎各位订阅关注。 目录 一、理解函数 二、函数的定义 1、语法 2、定义一个…...

在Ubuntu中使用Docker启动MySQL8的天坑

写在前面 简介&#xff1a; lower_case_table_names 是mysql设置大小写是否敏感的一个参数。 1.参数说明&#xff1a; lower_case_table_names0 表名存储为给定的大小和比较是区分大小写的 lower_case_table_names 1 表名存储在磁盘是小写的&#xff0c;但是比较的时候是不区…...

Python3.x String内置函数大全

文章目录 总结一下Python3.x字符串的常用系统函数&#xff0c;总共分为8类1. 大小写字母转换类的函数str.capitalize()str.title()str.lower()str.upper()str.swapcase() 2. 统计类的函数str.count(str1, beg 0,endlen(string)) 3. 匹配类的函数str.endswith(suffix, beg0, end…...

Go异常处理机制panic和recover

recover 使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数&#xff0c;然后将panic抛向上一层&#xff0c;直至程序crash。但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃&#xff0c;recover只有被defer后才是有意义的。 func main() { p…...

QMainwindow窗口

QMainwindow窗口 菜单栏在二级菜单中输入中文的方法给菜单栏添加相应的动作使用QMenu类的API方法添加菜单项分隔符也是QAction类 工具栏状态栏停靠窗口 菜单栏 只能有一个, 位于窗口的最上方 关于顶级菜单可以直接在UI窗口中双击, 直接输入文本信息即可, 对应子菜单项也可以通…...

P5735 【深基7.例1】距离函数

题目描述 给出平面坐标上不在一条直线上三个点坐标 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_1,y_1),(x_2,y_2),(x_3,y_3) (x1​,y1​),(x2​,y2​),(x3​,y3​)&#xff0c;坐标值是实数&#xff0c;且绝对值不超过 100.00&#xff0c;求围成的三角形周长。保留两…...

prometheus告警发送组件部署

一、前言 要实现Prometheus的告警发送需要通过alertmanager组件&#xff0c;当prometheus触发告警策略时&#xff0c;会将告警信息发送给alertmanager&#xff0c;然后alertmanager根据配置的策略发送到邮件或者钉钉中&#xff0c;发送到钉钉需要安装额外的prometheus-webhook…...

CAPL - XML和TestModule结合实现测试项可选

目录 目的:是否想实现如下面的功能呢? 一、.can和.cin文件中函数开发...

Latex安装与环境配置(TeXlive、TeXstudio与VS code的安装)编译器+编辑器与学习应用

TeXlive 配置Tex排版系统需要安装编译器+编辑器。TeX 的源代码是后缀为 .tex 的纯文本文件。使用任意纯文本编辑器,都可以修改 .tex 文件:包括 Windows 自带的记事本程序,也包括专为 TeX 设计的编辑器(TeXworks, TeXmaker, TeXstudio, WinEdt 等),还包括一些通用的文本编…...

STM32 F103C8T6学习笔记3:串口配置—串口收发—自定义Printf函数

今日学习使用STM32 C8T6的串口&#xff0c;我们在经过学习笔记2的总结归纳可知&#xff0c;STM32 C8T6最小系统板上有三路串口&#xff0c;如下图&#xff1a; 今日我们就着手学习如何配置开通这些串口进行收发&#xff0c;这里不讲串口通信概念与基础&#xff0c;可以自行网上…...

python中字符串内建函数篇4

一、ljust() 语法&#xff1a;str.ljust(width,[fillchar]) 参数说明&#xff1a; width – 指定字符串长度。 fillchar – 填充字符&#xff0c;默认为空格。 返回值&#xff1a;返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串。如果指定的长度小于原字符串…...

并发下如何使用redis存储列表数据

1、问题 今天在工作中遇到一个问题&#xff0c;需要查询表A&#xff0c;需要根据每天所处小时所在时段&#xff0c;返回不同的记录给前端展示&#xff0c;如0-2时是在昨日0到2时生成的记录&#xff0c;而2-4时则是在昨日2-4时生成的记录&#xff0c;每条记录有一个唯一的id。表…...

Leecode螺旋矩阵 II59

59.螺旋矩阵II 题目建议&#xff1a; 本题关键还是在转圈的逻辑&#xff0c;在二分搜索中提到的区间定义&#xff0c;在这里又用上了。 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 文章讲解&#xff1a;代码随想录 视频…...

echarts 横向柱状图

<template><div ref"chart" style"height: 100%"></div> </template><script> import * as echarts from "echarts"; var cate ["质量通病1", "质量通病2", "质量通病3", "质…...

Vue3 —— to 全家桶及源码学习

该文章是在学习 小满vue3 课程的随堂记录示例均采用 <script setup>&#xff0c;且包含 typescript 的基础用法 前言 本篇主要学习几个 api 及相关源码&#xff1a; toReftoRefstoRaw 一、toRef toRef(reactiveObj, key) 接收两个参数&#xff0c;第一个是 响应式对象…...

(第三篇) ansible-kubeadm在线安装高可以用集群()

ansible可以安装的KS8版本如下&#xff1a; 请按照此博客中的内容操作后&#xff0c;才可以通过下面的命令查询到版本。 [rootk8s-master01 ~]# yum list kubectl --showduplicates | sort -r kubectl.x86_64 1.20.0-0 kubern…...

flutter开发实战-颜色Color与16进制转换

flutter开发实战-颜色Color与16进制转换 一、颜色Color与16进制转换 代码如下 import dart:ui; class ColorUtil {/// 十六进制颜色&#xff0c;/// hex, 十六进制值&#xff0c;例如&#xff1a;0xffffff,/// alpha, 透明度 [0.0,1.0]static Color hexColor(int hex, {doub…...

Linux(进程地址空间)

进程地址空间 程序地址空间进程地址空间 程序地址空间 在Linux环境下&#xff0c;我们可以对上述程序空间地址进行验证&#xff1a; 运行程序&#xff0c;可以看到&#xff0c;我们就可以很好看出程序的地址空间的排布了&#xff1a; 进程地址空间 严格来说&#xff0c;我们…...

VLAN监控及常见问题排查

局域网&#xff0c;我们通常称为LAN&#xff0c;是一种由基于同一地理位置的设备组成的网络&#xff0c;可实现它们之间的通信&#xff0c;局域网的虚拟对应物是虚拟局域网或 VLAN。VLAN 增强了 LAN&#xff0c;提供了进行更改的灵活性、更高的可扩展性和更好的安全性。 使用 …...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践

前言&#xff1a;本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中&#xff0c;跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南&#xff0c;你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案&#xff0c;并结合内网…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践

01技术背景与业务挑战 某短视频点播企业深耕国内用户市场&#xff0c;但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大&#xff0c;传统架构已较难满足当前企业发展的需求&#xff0c;企业面临着三重挑战&#xff1a; ① 业务&#xff1a;国内用户访问海外服…...

Linux-进程间的通信

1、IPC&#xff1a; Inter Process Communication&#xff08;进程间通信&#xff09;&#xff1a; 由于每个进程在操作系统中有独立的地址空间&#xff0c;它们不能像线程那样直接访问彼此的内存&#xff0c;所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...

41道Django高频题整理(附答案背诵版)

解释一下 Django 和 Tornado 的关系&#xff1f; Django和Tornado都是Python的web框架&#xff0c;但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架&#xff0c;鼓励快速开发和干净、实用的设计。它遵循MVC设计&#xff0c;并强调代码复用。Django有…...

Cursor AI 账号纯净度维护与高效注册指南

Cursor AI 账号纯净度维护与高效注册指南&#xff1a;解决限制问题的实战方案 风车无限免费邮箱系统网页端使用说明|快速获取邮箱|cursor|windsurf|augment 问题背景 在成功解决 Cursor 环境配置问题后&#xff0c;许多开发者仍面临账号纯净度不足导致的限制问题。无论使用 16…...