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.pswp.cn/news/36085.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36085.shtml
英文地址,請注明出處:http://en.pswp.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.創建請求文件 該…