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 版本中新引入的可选链运算符(?.)和空值合并运算符(??)来提高程序的可读性。

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

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

相关文章

用户端Web自动化测试-L1

目录&#xff1a; Web自动化测试价值与体系环境安装与使用自动化用例录制自动化测试用例结构分析web浏览器控制常见控件定位方法强制等待与隐式等待常见控件交互方法自动化测试定位策略搜索功能自动化测试用户端Web自动化测试 1.Web自动化测试价值与体系 功能测试场景: UI 自…

IntelliJ Idea 编译时控制台上中文输出乱码

猜测原因是IDEA启动时未指定编码信息&#xff0c;故与系统编码保持一致&#xff08;windows中文系统默认为GBK编码&#xff09;,当以UTF-8编码进行编译在控制台会以GBK编码输出,从而导致乱码 解决方案 指定Idea启动时JVM的默认编码为UTF-8 Help -> Edit Custom Options P…

本地图片的image加密解密-Python 3.10-win10

本地图片的image加密解密- Python 3.10 pyt3int22 -根据1zip下图片批量生成加密的-物体识别.py import ioimport os import base64 import json # 指定图片文件夹 image_dir = "./1zip/" base64code_dir = "./base64code/" base64_to_dir = "./bas…

AUTOSAR规范与ECU软件开发(基础篇)2.5 AUTOSAR方法论

前言 AUTOSAR方法论(AUTOSAR Methodology) 中车用控制器软件的开发涉及系统级、 ECU级和软件组件级。 系统级主要考虑系统功能需求、 硬件资源、 系统约束, 然后建立系统架构; ECU级根据抽象后的信息对ECU进行配置; 系统级和ECU级设计的同时, 伴随着软件组件级的开发。 上…

Sql server还原失败(数据库正在使用,无法获得对数据库的独占访问权)

一.Sql server还原失败(数据库正在使用,无法获得对数据库的独占访问权) 本次测试使用数据库实例SqlServer2008r2版 错误详细&#xff1a; 标题: Microsoft SQL Server Management Studio ------------------------------ 还原数据库“Mvc_HNHZ”时失败。 (Microsoft.SqlServer.…

《甲午》观后感——GPT-3.5所写

《甲午》是一部令人深思的纪录片&#xff0c;通过生动的画面和真实的故事&#xff0c;向观众展示了中国历史上的一段重要时期。观看这部纪录片&#xff0c;我深受触动&#xff0c;对历史的认识也得到了深化。 首先&#xff0c;这部纪录片通过精心搜集的历史资料和珍贵的影像资料…

低成本搭建NAS,利用HFS进行内网穿透,实现公网访问

通过HFS低成本搭建NAS&#xff0c;并内网穿透实现公网访问 文章目录 通过HFS低成本搭建NAS&#xff0c;并内网穿透实现公网访问前言1.下载安装cpolar1.1 设置HFS访客1.2 虚拟文件系统 2. 使用cpolar建立一条内网穿透数据隧道2.1 保留隧道2.2 隧道名称2.3 成功使用cpolar创建二级…

JMS 消息队列接口基本使用指南

概述 介绍 JMS&#xff08;Java Message Service&#xff09;即 Java 消息服务应用程序接口&#xff0c;是一个 Java 平台中关于面向消息中间件&#xff08;MOM&#xff09;的 API&#xff0c;用于在两个应用程序之间&#xff0c;或分布式系统中发送消息&#xff0c;进行异步…

[保研/考研机试] KY103 2的幂次方 上海交通大学复试上机题 C++实现

题目链接&#xff1a; KY103 2的幂次方 https://www.nowcoder.com/share/jump/437195121691999575955 描述 Every positive number can be presented by the exponential form.For example, 137 2^7 2^3 2^0。 Lets present a^b by the form a(b).Then 137 is present…

k8s containerd 配置 http访问harbor image【最新--官方文档】

不看官方文档的代价&#xff1a;在搜索了很多中文资料发现配置了都不起作用&#xff0c;浪费了很多时间。 https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration The old CRI config pattern for specifying registry.mirrors and…

MySQL8安装和删除教程 保姆级(Windows)

下载 官网: mysql官网点击Downloads->MySQL Community(GPL) Downloads->MySQL Community Server(或者点击MySQL installer for Windows) Windows下有两种安装方式 在线安装 一般带有 web字样 这个需要联网离线安装 一般没有web字样 安装 下载好之后,版本号可以不一样&…

Postman中,既想传递文件,还想传递多个参数(后端)

需求:既想传文件又想传多个参数可以用以下方式实现

Django rest_framework Serializer中的create、Views中的create/perform_create的区别

Django rest_framework Serializer中的create、Views中的create/perform_create的区别 对于后端来说&#xff0c;前后端分离的方式能让前后端的开发都爽。和所有的爽一样&#xff0c;每爽一次都要付出一定的代价。而前后端分离的代价&#xff0c;就是后端要面对巨量的模块化的功…

C语言实现插入排序

什么是插入排序&#xff1f; 插入排序&#xff08;Insertion Sort&#xff09; 是一种简单且逐步构建有序序列的排序算法。它的思想是将数组分为两部分&#xff1a;已排序的部分和未排序的部分。初始时&#xff0c;已排序部分只包含数组的第一个元素&#xff0c;然后逐步将未排…

Process.Start 报错

Process.Start 报错 System.Diagnostics.Process.StartWithShellExecuteEx Process.Start 为什么会引发“系统找不到指定的文件”异常 Process.Start 报错 找不到路径 ,System.ComponentModel.Win32Exception:“系统找不到指定的文件。 问题1、 在WinForm中可能是权限问题&…

做了这件事,精准拿捏企业资产管理!

资产管理系统是一种为组织和个人提供管理各类资产的重要工具。无论是金融资产还是实物资产&#xff0c;这些都构成了一个实体或个人财务状况的重要组成部分。 无论是企业寻求优化其固定资产维护&#xff0c;还是个人希望更好地管理他们的投资组合&#xff0c;资产管理系统在现代…

NZ系列工具NZ02:VBA读取PDF使用说明

【分享成果&#xff0c;随喜正能量】时光绽放并蒂莲&#xff0c;更是一份殷殷嘱托&#xff0c;更是一份诚挚祝福&#xff0c;是一份时光馈赠&#xff0c;又是一份时光陪伴。。 我的教程一共九套及VBA汉英手册一部&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解…

“深入解析JVM:探索Java虚拟机的工作原理与优化技巧“

标题&#xff1a;深入解析JVM&#xff1a;探索Java虚拟机的工作原理与优化技巧 摘要&#xff1a;本文将深入探讨Java虚拟机&#xff08;JVM&#xff09;的工作原理、内部结构以及如何优化Java应用程序的性能。我们将介绍JVM的主要组件&#xff0c;包括类加载器、运行时数据区域…

关于openssl SM2 ECC以及密钥生成和签名验签

SM2是基于ECC的国密算法,本身也是ECC算法。 openssl生成ECC公私钥并签名验签 #!/bin/sh openssl ecparam -genkey -name prime256v1 -out private.pem #print pri #openssl ec -in private.pem -text -noout openssl ec -in private.pem -pubout -out public.pem #gen test.…

uniapp+uview封装小程序请求

提要&#xff1a; uniapp项目引入uview库 此步骤不再阐述 1.创建环境文件 env.js&#xff1a; let BASE_URL;if (process.env.NODE_ENV development) {// 开发环境BASE_URL 请求地址; } else {// 生产环境BASE_URL 请求地址; }export default BASE_URL; 2.创建请求文件 该…