JavaScript斷言與類型守衛(wèi)及聯(lián)合聲明超詳細介紹
一、TypeScript 斷言
1.1 類型斷言
個人理解的斷言,就是斷定某一個值的類型,此時TypeScript以你所給出的值類型為準,而非TypeScrip的推論
在一些復雜的類型聲明 變成具體實現(xiàn)時往往用得到 并且避免很多類型過于復雜的情況
類型斷言有兩種形式:
1.尖括號語法
const someValue: any = "this is a string"; let strLength: number = (<{a:number}>someValue).a;
2.as 語法
這個用的比較多
let someValue = "this is a string" as string; let strLength: number = someValue.length;
1.2 非空斷言
TypeScript 提供了一個特殊的語法,可以在不做任何檢查的情況下,從類型中移除 null 和 undefined,這就是在任意表達式后面寫上 ! ,這是一個有效的類型斷言,表示它的值不可能是 null 或者 undefined:
1.3 確定賦值斷言
在 TypeScript 2.7 版本中引入了確定賦值斷言,即允許在實例屬性和變量聲明后面放置一個 !
號,從而告訴 TypeScript 該屬性會被明確地賦值。為了更好地理解它的作用,我們來看個具體的例子:
let x: number; console.log(2 * x);
很明顯會有報錯,因為在賦值前使用變量,要解決該問題,我們可以使用確定賦值斷言:
let x!: number; console.log(2 * x);
二、類型守衛(wèi)
類型保護是可執(zhí)行運行時檢查的一種表達式,用于確保該類型在一定的范圍內(nèi)。 換句話說,類型保護可以保證一個字符串是一個字符串,盡管它的值也可以是一個數(shù)值。
如
// function add(padding: number | string) { return padding + 10; //運算符“+”不能應用于類型“string | number”和“number”。 }
類型保護與特性檢測并不是完全不同,其主要思想是嘗試檢測屬性、方法或原型,以確定如何處理值。目前主要有四種的方式來實現(xiàn)類型保護:
2.1 in關(guān)鍵字
js中的in 關(guān)鍵字 如果指定的屬性在指定的對象或其原型鏈中,則 in 運算符返回 true。
const car = { make: 'Honda', model: 'Accord', year: 1998 }; console.log('make' in car); //true delete car.make; if ('make' in car === false) { car.make = 'Suzuki'; } console.log(car.make); //Suzuki
typescript也是類似的
interface Admin { name: string; privileges: string[]; } interface Employee { name: string; startDate: Date; } type UnknownEmployee = Employee | Admin; function printEmployeeInformation(emp: UnknownEmployee) { console.log("Name: " + emp.name); if ("privileges" in emp) { console.log("Privileges: " + emp.privileges); } if ("startDate" in emp) { console.log("Start Date: " + emp.startDate); } }
2.2 typeof關(guān)鍵字
// “number”, “string”, “boolean” , “symbol”
function padLeft(value: string, padding: string | number) { if (typeof padding === "number") { return Array(padding + 1).join(" ") + value; } if (typeof padding === "string") { return padding + value; } throw new Error(`Expected string or number, got '${padding}'.`); }
typeof
類型保護只支持兩種形式:typeof v === "typename"
和 typeof v !== typename
,"typename"
必須是 "number"
, "string"
, "boolean"
或 "symbol"
。 但是 TypeScript 并不會阻止你與其它字符串比較,語言不會把那些表達式識別為類型保護。
2.3 instanceof 關(guān)鍵字
當聯(lián)合類型中使用的是 class 而不是 interface 時,instanceof 語法就派上用場了,通過 instanceof 語法可以區(qū)分不同的 class 類型。
class Bird { // 獨有方法 fly() {}; // 共有方法 layEggs() {}; } class Fish { // 獨有方法 swim() {}; // 共有方法 layEggs() {}; } function getSmallPet(): Fish | Bird { // ... } let pet = getSmallPet(); pet.layEggs(); // 正常 // 使用 in 語法進行 if (pet instanceof Bird) { pet.fly() } else { pet.swim() }
2.4 **自定義類型保護的類型謂詞
function isNumber(x: any): x is number { return typeof x === "number"; } function isString(x: any): x is string { return typeof x === "string"; } function isFish(pet: Fish | Bird): pet is Fish { return (<Fish>pet).swim !== undefined; } if (pagination.pageSize != _pagination.pageSize && (<ListObjProps<T, K>>listProps).pagination?.pageSize) { localStorage.setItem(FeManagePageSize, _pagination.pageSize?.toString() || '10') }
三、聯(lián)合類型和類型別名
3.1 聯(lián)合類型
聯(lián)合類型通常與 null
或 undefined
一起使用:
const abc = (name: string | undefined) => { };
例如,這里 name
的類型是 string | undefined
意味著可以將 string
或 undefined
的值傳遞給abc
函數(shù)。
abc("semlinker"); abc(undefined);
通過這個示例,你可以憑直覺知道類型 A 和類型 B 聯(lián)合后的類型是同時接受 A 和 B 值的類型。此外,對于聯(lián)合類型來說,你可能會遇到以下的用法:
let num: 1 | 2 = 1; type Type = 'click' | 'doubleClick' | 'mousemove';
3.2 可辨識聯(lián)合
TypeScript 可辨識聯(lián)合(Discriminated Unions)類型,也稱為代數(shù)數(shù)據(jù)類型或標簽聯(lián)合類型。它包含 3 個要點:可辨識、聯(lián)合類型和類型守衛(wèi)。
這種類型的本質(zhì)是結(jié)合聯(lián)合類型和字面量類型的一種類型保護方法。如果一個類型是多個類型的聯(lián)合類型,且多個類型含有一個公共屬性,那么就可以利用這個公共屬性,來創(chuàng)建不同的類型保護區(qū)塊。
1. 可辨識
可辨識要求聯(lián)合類型中的每個元素都含有一個單例類型屬性,比如:
enum CarTransmission { Automatic = 200, Manual = 300 } interface Motorcycle { vType: "motorcycle"; make: number; } interface Car { vType: "car"; transmission: CarTransmission } interface Truck { vType: "truck"; capacity: number; }
在上述代碼中,我們分別定義了 Motorcycle
、 Car
和 Truck
三個接口,在這些接口中都包含一個 vType
屬性,該屬性被稱為可辨識的屬性,而其它的屬性只跟特性的接口相關(guān)。
2. 聯(lián)合類型
基于前面定義了三個接口,我們可以創(chuàng)建一個 Vehicle
聯(lián)合類型:
type Vehicle = Motorcycle | Car | Truck;
現(xiàn)在我們就可以開始使用 Vehicle
聯(lián)合類型,對于 Vehicle
類型的變量,它可以表示不同類型的車輛。
3. 類型守衛(wèi)
下面我們來定義一個 evaluatePrice
方法,該方法用于根據(jù)車輛的類型、容量和評估因子來計算價格,具體實現(xiàn)如下:
const EVALUATION_FACTOR = Math.PI; function evaluatePrice(vehicle: Vehicle) { return vehicle.capacity * EVALUATION_FACTOR; } const myTruck: Truck = { vType: "truck", capacity: 9.5 }; evaluatePrice(myTruck);
原因是在 Motorcycle 接口中,并不存在 capacity
屬性,而對于 Car 接口來說,它也不存在 capacity
屬性。那么,現(xiàn)在我們應該如何解決以上問題呢?這時,我們可以使用類型守衛(wèi)。下面我們來重構(gòu)一下前面定義的 evaluatePrice
方法,重構(gòu)后的代碼如下:
function evaluatePrice(vehicle: Vehicle) { switch(vehicle.vType) { case "car": return vehicle.transmission * EVALUATION_FACTOR; case "truck": return vehicle.capacity * EVALUATION_FACTOR; case "motorcycle": return vehicle.make * EVALUATION_FACTOR; } }
在以上代碼中,我們使用 switch
和 case
運算符來實現(xiàn)類型守衛(wèi),從而確保在 evaluatePrice
方法中,我們可以安全地訪問 vehicle
對象中的所包含的屬性,來正確的計算該車輛類型所對應的價格。
3.3 類型別名
類型別名用來給一個類型起個新名字。
type Message = string | string[]; let greet = (message: Message) => { }; ACTOR; } }
在以上代碼中,我們使用 switch
和 case
運算符來實現(xiàn)類型守衛(wèi),從而確保在 evaluatePrice
方法中,我們可以安全地訪問 vehicle
對象中的所包含的屬性,來正確的計算該車輛類型所對應的價格。
到此這篇關(guān)于JavaScript斷言與類型守衛(wèi)及聯(lián)合聲明超詳細介紹的文章就介紹到這了,更多相關(guān)JS斷言與類型守衛(wèi)及聯(lián)合聲明內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript基于jQuery UI實現(xiàn)選中區(qū)域拖拽效果
這篇文章主要介紹了Javascript基于jQuery UI實現(xiàn)選中區(qū)域拖拽效果的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11JS target與currentTarget區(qū)別說明
target在事件流的目標階段;currentTarget在事件流的捕獲,目標及冒泡階段。只有當事件流處在目標階段的時候,兩個的指向才是一樣的,而當處于捕獲和冒泡階段的時候,target指向被單擊的對象而currentTarget指向當前事件活動的對象(一般為父級)。2011-08-08