TypeScript 非空斷言
發(fā)布于?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!;
}
二、非空斷言操作符簡介
在上下文中當(dāng)類型檢查器無法斷定類型時,一個新的后綴表達式操作符 !
可以用于斷言操作對象是非 null 和非undefined 類型。具體而言,x!
將從 x 值域中排除 null
和 undefined
。
下面我們來介紹一下非空斷言操作符的一些使用場景和注意事項。
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; // Error
const ignoreUndefinedAndNull: string = maybeString!; // Ok
}
2.2 調(diào)用函數(shù)時忽略 undefined 類型
type NumGenerator = () => number;
function myFunc(numGenerator: NumGenerator | undefined) {
// Object is possibly 'undefined'.
// Cannot invoke an object which is possibly 'undefined'.
const num1 = numGenerator(); // Error
const 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 代碼中,!
非空斷言操作符被移除了,所以在瀏覽器中執(zhí)行以上代碼,在控制臺會輸出 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 function
at 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 并不是函數(shù)對象,所以就不能正常調(diào)用。
需要注意的是,非空斷言操作符僅在啟用
strictNullChecks
標(biāo)志的時候才生效。當(dāng)關(guān)閉該標(biāo)志時,編譯器不會檢查 undefined 類型和 null 類型的賦值。
三、非空斷言操作符使用示例
在以下示例中,首先我們使用 TypeScript 類型別名定義了一個 ListNode
類型,用于表示鏈表節(jié)點。該類型包含 data
和 next
兩個屬性,分別表示當(dāng)前節(jié)點的值和下個節(jié)點。之后,我們還定義了以下兩個函數(shù):
- addNext(node: ListNode):用于添加下一個節(jié)點;
- setNextValue(node: ListNode, value: number):用于設(shè)置下一個節(jié)點的值。
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
}
對于以上代碼盡管我們知道在調(diào)用 addNext
方法后,node.next 屬性會被定義,但 TypeScript 在 node.next.data = value
這行代碼中并不能推斷出這些。這時候我們可以使用非空斷言運算符 !
來斷言 node.next 并不是 undefined,并且使編譯器警告無效:
function setNextValue(node: ListNode, value: number) {
addNext(node);
node.next!.data = value;
}
接著我們繼續(xù)看一個示例,假設(shè)你有一個表示 AJAX 請求過程的 UI 狀態(tài)。它要么處于初始狀態(tài)(initial),要么處于掛起狀態(tài)(pending),要么處于完成狀態(tài)(complete),要么處于錯誤狀態(tài)(error)。只有在完成狀態(tài)下才有響應(yīng),否則為 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
}
}
雖然我們知道當(dāng)請求的狀態(tài)為 complete
時,響應(yīng)對象不會為 null,但 TypeScript 并無法感知這些,所以我們還需要使用非空斷言 ajaxState.response!.length
來忽略空值并使編譯器警告無效。對于這種場景,其實有一個更好的解決方案,即使用可辨識聯(lián)合:文章來源:http://www.zghlxwxcb.cn/news/detail-645717.html
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);
}
}
通過引入可辨識聯(lián)合類型,我們把為 null 和非 null 的響應(yīng)完美的區(qū)分開來,還避免了再次使用非空斷言,此外還大大提高了程序的可讀性。在 TypeScript 實際項目的開發(fā)過程中,除了使用非空斷言(!)之外,讀者還可以使用 TypeScript 3.7 版本中新引入的可選鏈運算符(?.)和空值合并運算符(??)來提高程序的可讀性。文章來源地址http://www.zghlxwxcb.cn/news/detail-645717.html
到了這里,關(guān)于TypeScript 非空斷言的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!