TS條件類型、斷言及名義類型

?文章將討論處理類型的幾個高級模式,包括模擬名義類型的類型烙印、利用條件類型的分配性質在類型層面操作類型,以及安全地擴展原型。

1 函數類型

TS在推導元組的類型時會放寬要求,推導出的結果盡量寬泛,不在乎元組的長度和各位置的類型:

let a = [“hello”,false,1]; // (string | boolean | number)[]

我們有時希望推導結果更嚴格些,比如上面的類型應該為 [string,boolean,number]。我們可以使用類型斷言或者as const來收窄推導結果,我們還可以自定義函數,來實現元組類型收窄:

function tuple<T extends unknown[]>(...t: T) {return t;
}
let t1 = tuple(2,false); // [number,boolean]

1.1 自定義類型防護措施

開發中,我們時常需要判斷對象的類型,我們會寫一個函數來進行判斷:

function isString(input: unknown) {return typeof input === 'string';
}

但是這個函數在某些場景中,可能會達不到我們的預期效果:

function fun(input: string | number) {if (isString(input)) {input.toUpperCase();//報錯 Property toUpperCase does not exist on type string | number// Property toUpperCase does not exist on type number}
}

這是因為TS類型細化能力有限,只能細化當前作用域中變量的類型,即上面代碼中,TS只能在isString函數中來保證input是個string類型。

TS內置特性:類型防護措施。這是typeof和instanceof細化類型的背后機制。我們通過自定義類型防護措施來實現類型的細化在作用域之間轉移:

function isString(a: unknown):a is string {return typeof a === 'string';
}
function fun(input: number | string) {if (isString(input)) {input.toUpperCase();}
}

2 條件類型

條件類型是聲明一個依賴類型U和V的類型T,如果 U <: V,就把T賦值給A,否則賦值給B。例如:

type IsString<T> = T extends string ? true : false。

type A = isString<number>; // false

type A = isString<string>; // true

條件類型使用廣泛,可以使用類型的地方幾乎都能使用條件類型。

type WithoutArrayType<T,U> = T extends U ? never : T[];
type T1 = WithoutArrayType<string | number | boolean, boolean>; // string[] | number[]

2.1 infer 關鍵字聲明泛型

在條件類型中不能適用尖括號(<T>)來聲明范型,而是使用infer關鍵字。

type ElementType<T> = T extends unknown[] ? T[number] : T;
type ElementType2<T> = T extends (infer U)[] ? U : T; // 等效上面type T1 = ElementType<number[]>; // number
type T2 = ElementType2<string[][]>; //string[]

2.2 內置的條件類型

Exclude<T,U>: 返回在T中而不在U中的類型。

type ExcludeType = Exclude<string | number | boolean, number>; // string | boolean

Extract<T,U>: 返回T中可賦值給U的類型。

type ExtractType = Extract< number | boolean, string | number | 'x'>; // number

NonNullable<T>: 從T中排出null和undefined。

type A = { a? :number,b: string | null};
type aType = NonNullable<A["a"]>; // number
type A1 = NonNullable<A>; // A & {}let a1:A1 = {a:1,b:1};
let a2:A1 = {}; // Property b is missing in type {} but required in type A
let a3:A1 = {b:null};

ReturnType<F>: 計算函數的返回類型(不適用泛型和重載的函數)。

type Fun = () => string;
type T1 = ReturnType<Fun>; // string

InstanceType<C>: 返回類構造方法的實例類型。

type CustomClass = {new(): C}
type C = {name:"user"};
type T = InstanceType<CustomClass>; // {name: "user"}

3 斷言

在沒有足夠時間把所有類型都規劃好,但是我們希望TS不要因為這個而讓我們程序運行不起來,我們可以使用斷言的方式(但要盡量少用,如果大量依賴這些,說明項目需要重構了)。

1)類型斷言。有兩種方式:as 和尖括號。

function fun(input: string | number) {let str = input as string;// stringlet str2 = <string> input; // string
}

2)非空斷言。

type Student = {id?: number};
let s:Student = {};
let s2: Student = {id: 2};
function fun2(id: number) {}
fun2(s.id!);
fun2(s2.id!);
fun2(s2.id); // 報錯 Argument of type 'number | undefined' is not assignable to parameter of type 'number'.

3)明確賦值斷言。TS通過明確賦值檢查確保使用變量時已經為其賦值。

我們在定義一個變量時,如果在沒有為其賦值而使用它,那么TS將報錯。

class Student{name: stringshowName() {console.log(this.name);}
}let student = new Student();
student.showName(); // 報錯? Property 'name' has no initializer and is not definitely assigned in the constructor.

明確賦值,是指在變量名后面加個”!“符號,來告訴TS,我已經確保,在使用這個變量之前,我已經為它賦值。

class Student{name!: stringshowName() {console.log(this.name);}
}let student = new Student();
student.showName(); // undefined

4 名義類型

TS 是結構化類型不是名義類型系統,即TS只根據類型結構來判斷類型而不是類型名稱。而在Java中,是根據類名來確定類型的。比如Man 和 People,在TS中,如果這兩個類型的結構是一樣的,那么它們是同一個類型,而在Java中,因為它們名字不同,就注定它們不是同一個類型。

雖然在TS中,通過結構類型給予了開發者很多方便,但是有時名義類型能發揮的作用是結構類型很難替代的:

定義一個函數,要求參數為一個StudentID類型的字符串。而這個StudentID本質上也是字符串類型。

我們可以使用類型烙印技術模擬實現。

4.1 類型烙印

類型烙印即給特定類型一個唯一結構,來讓它從其他相似類型結構中區別開。

type StudentID = string & {readonly brand: unique symbol};
function StudentID(id:string) {return id as StudentID;
}function showStudentId(id: StudentID) {}let id = StudentID("123"); // StudentID
showStudentId(id);
showStudentId("123"); // 報錯? Argument of type string is not assignable to parameter of type StudentID
//Type string is not assignable to type { readonly brand: unique symbol; }

類型烙印降低了運行時的開銷,是一種編譯時結構。

多數應用沒必要使用這個,不過,對于大型應用或者處理容易混淆的類型時,帶烙印的類型可以極大地提升程序的安全性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/211404.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211404.shtml
英文地址,請注明出處:http://en.pswp.cn/news/211404.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Cloud Gateway使用和配置

Spring Cloud Gateway是Spring官方基于Spring 5.0&#xff0c;Spring Boot 2.0和Project Reactor等技術開發的網關&#xff0c;Spring Cloud Gateway旨在為微服務架構提供一種簡單而有效的統一的API路由管理方式。Spring Cloud Gateway作為Spring Cloud生態系中的網關&#xff…

Linux 基礎IO

文章目錄 前言基礎IO定義系統IO接口文件描述符重定向原理緩沖區刷新 前言 要知道每個函數/接口的全部參數和返回值建議去官網或者直接在Linux的man手冊中查&#xff0c;這不是復制粘貼函數用法的文章。 C語言文件讀寫介紹鏈接 基礎IO定義 IO是Input/Output的縮寫&#xff0c…

optional

參考資料&#xff1a; Java8 Optional用法和最佳實踐 - 掘金 一、背景 根據Oracle文檔&#xff0c;Optional是一個容器對象&#xff0c;可以包含也可以不包含非null值。Optional在Java 8中引入&#xff0c;目的是解決 NullPointerExceptions的問題。本質上&#xff0c;Optio…

2024年網絡安全競賽-網站滲透

網站滲透 (一)拓撲圖 1.使用滲透機對服務器信息收集,并將服務器中網站服務端口號作為flag提交; 使用nmap工具對靶機進行信息收集 2.使用滲透機對服務器信息收集,將網站的名稱作為flag提交; 訪問頁面即可 3.使用滲透機對服務器滲透,將可滲透頁面的名稱作為flag提交…

Python:核心知識點整理大全5-筆記

目錄 2. 使用方法pop()刪除元素 3. 彈出列表中任何位置處的元素 4. 根據值刪除元素 3 章 列表簡介 3.3 組織列表 3.3.1 使用方法 sort()對列表進行永久性排序 3.3.2 使用函數 sorted()對列表進行臨時排序 3.3.3 倒著打印列表 3.3.4 確定列表的長度 3.5 小結 2. 使用方…

軟件測試:測試用例八大要素模板

一、通用測試用例八要素 1、用例編號&#xff1b; 2、測試項目&#xff1b; 3、測試標題&#xff1b; 4、重要級別&#xff1b; 5、預置條件&#xff1b; 6、測試輸入&#xff1b; 7、操作步驟&#xff1b; 8、預期輸出 二、具體分析通用測試用例八要素 1、用例編號 一般是數字…

[NAND Flash 2.1] NAND Flash 閃存改變了現代生活

依公知及經驗整理&#xff0c;原創保護&#xff0c;禁止轉載。 專欄 《深入理解NAND Flash》 <<<< 返回總目錄 <<<< ? 1989年NAND閃存面世了&#xff0c;它曾經且正在改變了我們的日常生活。 NAND 閃存發明之所以偉大&#xff0c;是因為&#xff0c…

一個CV算法工程師在技術方面的小反思

極市導讀 正如作者所說,做一個算法工程師最重要的素質是在海量的算法方案中理解,吃透那些真正的干貨,然后不斷在實踐中去驗證,并總結吸收到自己的腦子里。本文記錄了作者在算法工程師這個崗位上一年后總結的一些關于技術上的經驗總結。>>加入極市CV技術交流群,走在計…

怎樣解決編譯后的exe文件運行時產生的錯誤?

編譯后的exe文件運行時&#xff0c;錯誤如下錯誤提示&#xff1a;Traceback (most recent call last):File "pd.py", line 1, in <module>from pdf2docx import parse ModuleNotFoundError: No module named pdf2docx 怎樣解決&#xff1f; 這個錯誤提示表明…

java數據結構面試題

1.棧和隊列的共同特點是&#xff08;只允許在端點處插入和刪除元素&#xff09; 4.棧通常采用的兩種存儲結構是&#xff08;線性存儲結構和鏈表存儲結構&#xff09; 5.下列關于棧的敘述正確的是&#xff08;D&#xff09; A.棧是非線性結構 B.棧是一種樹狀結構 C.棧具有先進先…

蘋果OS X系統介紹(Mac OS --> Mac OS X --> OS X --> macOS)

文章目錄 OS X系統介紹歷史與版本架構內核與低級系統圖形&#xff0c;媒體和用戶界面應用程序和服務 特性用戶友好強大的命令行安全性集成與互操作性 總結 OS X系統介紹 OS X是由蘋果公司為Macintosh計算機系列設計的基于UNIX的操作系統。其界面友好&#xff0c;易于使用&…

使用 nohup java - jar 不輸出日志

要在使用nohup java -jar命令時不輸出日志&#xff0c;可以將標準輸出和標準錯誤輸出重定向到特殊設備文件/dev/null。這樣做將會丟棄所有的輸出。 以下是在Linux中使用nohup java -jar命令并禁止輸出日志的示例&#xff1a; 復制代碼 nohup java -jar your-application.jar …

Python可視化(二)——Seaborn

Seaborn是一個基于matplotlib的可視化庫&#xff0c;其為用戶提供了高級接口&#xff0c;并且該工具還深度集成了pandas的數據結構。并且該工具該集成了很多數據庫&#xff0c;配合官網給出的代碼示例&#xff0c;可以更方便的進行操作。 官網對它的介紹為&#xff1a; Seabo…

Servlet學習筆記

簡介 瀏覽器請求處理流程&#xff1a;瀏覽器發請求 > 服務器tomcat( > 應用程序 ( > servlet) ) Servlet應用的三大作用域&#xff1a;request&#xff0c;session&#xff0c;application tomcat存放項目的層級結構 注釋&#xff1a;servlet原引用包名 javax.serv…

卡爾曼濾波器

歡迎訪問我的博客首頁。 卡爾曼濾波器 1. 參考 1. 參考 卡爾曼濾波器&#xff0c;B 站&#xff0c;2020。擴展卡爾曼濾波器&#xff0c;CSDN&#xff0c;2023。

Git的安裝以及SSH配置

前言 近期工作需要&#xff0c;所以版本管理工具要用到Git&#xff0c;某些操作需要ssh進行操作&#xff0c;在某次操作中遇到&#xff1a;git bash報錯&#xff1a;Permission denied, please try again。經排查是ssh沒有配置我的key&#xff0c;所以就借著這篇文章整理了一下…

WorkPlus即時通訊,讓溝通零障礙!企業協作更高效

如今&#xff0c;隨著信息技術的快速發展&#xff0c;企業對于高效溝通和即時協作的需求也日益增長。在這個數字化時代&#xff0c;WorkPlus作為一款領先的企業級移動辦公平臺&#xff0c;以其強大的即時通訊功能和卓越的用戶體驗&#xff0c;成功為企業打造了高效溝通的新時代…

input = torch.randn(20, 2, 11, 11, 32)輸出形式

input torch.randn(20, 2, 11, 11, 32) m torch.nn.AdaptiveAvgPool3d((1,1, 32)) xm(input) print(x.shape) 結果&#xff1a; 也就是不用管批次和通道數

pico示波器使用

文章目錄 Pico示波器保存波形Pico示波器錄制數據Pico示波器解析CAN報文Pico示波器保存波形 Pico示波器可以通過以下步驟保存波形: 在示波器上選擇要保存的波形。連接示波器到計算機上,可以使用USB或者Ethernet連接。打開PicoScope軟件,選擇“File”菜單,然后選擇“Save As…

Python開發運維:Python垃圾回收機制

目錄 一、理論 1.Python垃圾回收機制 一、理論 1.Python垃圾回收機制 &#xff08;1&#xff09;引?計數器 1&#xff09;環狀雙向鏈表 refchain 在python程序中創建的任何對象都會放在refchain鏈表中。 name "david" age 20 hobby ["籃球",游泳…