色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一文詳細了解類型體操

我快閉嘴 ? 來源:OSC開源社區 ? 作者:OSC開源社區 ? 2022-09-27 10:07 ? 次閱讀

今天給大家分享的主題是一起來做類型體操。

主要分為 4 個部分進行介紹:

  1. 類型體操的背景,通過背景了解為什么要在項目中加入類型體操;
  2. 了解類型體操的主要類型、運算邏輯、和類型套路;
  3. 類型體操實踐,解析 TypeScript 內置高級類型,手寫 ParseQueryString 復雜類型;
  4. 小結,綜上分享,沉淀結論。

一、背景

在背景章節介紹的是什么是類型,什么是類型安全,怎么實現類型安全,什么是類型體操?

以了解類型體操的意義。

1. 什么是類型?

了解什么是類型之前,先來介紹兩個概念:

  • 不同類型變量占據的內存大小不同

boolean 類型的變量會分配 4 個字節的內存,而 number 類型的變量則會分配 8 個字節的內存,給變量聲明了不同的類型就代表了會占據不同的內存空間。

  • 不同類型變量可做的操作不同

number 類型可以做加減乘除等運算,boolean 就不可以,復合類型中不同類型的對象可用的方法不同,比如 Date 和 RegExp,變量的類型不同代表可以對該變量做的操作就不同。

綜上,可以得到一個簡單的結論就是,類型就是編程語言提供對不同內容的抽象定義

2. 什么是類型安全?

了解了類型的概念后,那么,什么是類型安全呢?

一個簡單的定義就是,類型安全就是只做該類型允許的操作。比如對于 boolean 類型,不允許加減乘除運算,只允許賦值 true、false。

當我們能做到類型安全時,可以大量的減少代碼中潛在的問題,大量提高代碼質量。

3. 怎么實現類型安全?

那么,怎么做到類型安全?

這里介紹兩種類型檢查機制,分別是動態類型檢查和靜態類型檢查。

3.1 動態類型檢查

Javascript 就是典型的動態類型檢查,它在編譯時,沒有類型信息,到運行時才檢查,導致很多隱藏 bug。

6e1169d8-3d9e-11ed-9e49-dac502259ad0.jpg

3.2 靜態類型檢查

TypeScript 作為 Javascript 的超集,采用的是靜態類型檢查,在編譯時就有類型信息,檢查類型問題,減少運行時的潛在問題。

6e1fce4c-3d9e-11ed-9e49-dac502259ad0.jpg

4. 什么是類型體操

上面介紹了類型的一些定義,都是大家熟悉的一些關于類型的背景介紹,這一章節回歸到本次分享的主題概念,類型體操。

了解類型體操前,先介紹 3 種類型系統。

4.1 簡單類型系統

簡單類型系統,它只基于聲明的類型做檢查,比如一個加法函數,可以加整數也可以加小數,但在簡單類型系統中,需要聲明 2 個函數來做這件事情。

intadd(inta,intb){
returna+b
}

doubleadd(doublea,doubleb){
returna+b
}

4.2 泛型類型系統

泛型類型系統,它支持類型參數,通過給參數傳參,可以動態定義類型,讓類型更加靈活。

Tadd(Ta,Tb){
returna+b
}

add(1,2)
add(1.1,2.2)

但是在一些需要類型參數邏輯運算的場景就不適用了,比如一個返回對象某個屬性值的函數類型。

functiongetPropValue<T>(obj:T,key){
returnobj[key]
}

4.3 類型編程系統

類型編程系統,它不僅支持類型參數,還能給類型參數做各種邏輯運算,比如上面提到的返回對象某個屬性值的函數類型,可以通過 keyof、T[K] 來邏輯運算得到函數類型。

functiongetPropValue<
??Textendsobject,
KeyextendskeyofT
>(obj:T,key:Key):T[Key]{
returnobj[key]
}

總結上述,類型體操就是類型編程,對類型參數做各種邏輯運算,以產生新的類型

之所以稱之為體操,是因為它的復雜度,右側是一個解析參數的函數類型,里面用到了很多復雜的邏輯運算,等先介紹了類型編程的運算方法后,再來解析這個類型的實現。

二、了解類型體操

熟悉完類型體操的概念后,再來繼續了解類型體操有哪些類型,支持哪些運算邏輯,有哪些運算套路。

1. 有哪些類型

類型體操的主要類型列舉在圖中。TypeScript 復用了 JS 的基礎類型和復合類型,并新增元組(Tuple)、接口(Interface)、枚舉(Enum)等類型,這些類型在日常開發過程中類型聲明應該都很常用,不做贅述。

6e374388-3d9e-11ed-9e49-dac502259ad0.jpg
//元組(Tuple)就是元素個數和類型固定的數組類型
typeTuple=[number,string];

//接口(Interface)可以描述函數、對象、構造器的結構:
interfaceIPerson{
name:string;
age:number;
}

classPersonimplementsIPerson{
name:string;
age:number;
}

constobj:IPerson={
name:'aa',
age:18
}

//枚舉(Enum)是一系列值的復合:
enumTranspiler{
Babel='babel',
Postcss='postcss',
Terser='terser',
Prettier='prettier',
TypeScriptCompiler='tsc'
}

consttranspiler=Transpiler.TypeScriptCompiler;

2. 運算邏輯

重點介紹的是類型編程支持的運算邏輯。

TypeScript 支持條件、推導、聯合、交叉、對聯合類型做映射等 9 種運算邏輯。

  • 條件:T extends U ? X : Y

條件判斷和 js 邏輯相同,都是如果滿足條件就返回 a 否則返回 b。

//條件:extends?:
//如果T是2的子類型,那么類型是true,否則類型是false。
typeisTwo=Textends2?true:false;
//false
typeres=isTwo<1>;
  • 約束:extends

通過約束語法 extends 限制類型。

//通過TextendsLength約束了T的類型,必須是包含length屬性,且length的類型必須是number。
interfaceLength{
length:number
}

functionfn1<TextendsLength>(arg:T):number{
returnarg.length
}
  • 推導:infer

推導則是類似 js 的正則匹配,都滿足公式條件時,可以提取公式中的變量,直接返回或者再次加工都可以。

//推導:infer
//提取元組類型的第一個元素:
//extends約束類型參數只能是數組類型,因為不知道數組元素的具體類型,所以用unknown。
//extends判斷類型參數T是不是[inferF,...inferR]的子類型,如果是就返回F變量,如果不是就不返回
typeFirst=Textends[inferF,...inferR]?F:never;
//1
typeres2=First<[1,2,3]>;
  • 聯合:|

聯合代表可以是幾個類型之一。

typeUnion=1|2|3
  • 交叉:&

交叉代表對類型做合并。

typeObjType={a:number}&{c:boolean}

keyof 用于獲取某種類型的所有鍵,其返回值是聯合類型。

//consta:'name'|'age'='name'
consta:keyof{
name:string,
age:number
}='name'
  • 索引訪問:T[K]

T[K] 用于訪問索引,得到索引對應的值的聯合類型。

interfaceI3{
name:string,
age:number
}

typeT6=I3[keyofI3]//string|number

  • 索引遍歷: in

in 用于遍歷聯合類型。

constobj={
name:'tj',
age:11
}

typeT5={
[Pinkeyoftypeofobj]:any
}

/*
{
name:any,
age:any
}
*/
  • 索引重映射: as

as 用于修改映射類型的 key。

//通過索引查詢keyof,索引訪問t[k],索引遍歷in,索引重映射as,返回全新的key、value構成的新的映射類型
typeMapType={
[
KeyinkeyofT
as`${Key&string}${Key&string}${Key&string}`
]:[T[Key],T[Key],T[Key]]
}
//{
//aaa:[1,1,1];
//bbb:[2,2,2];
//}
typeres3=MapType<{?a:1,b:2}>

3. 運算套路

根據上面介紹的 9 種運算邏輯,我總結了 4 個類型套路。

  • 模式匹配做提取;
  • 重新構造做變換;
  • 遞歸復用做循環;
  • 數組長度做計數。

3.1 模式匹配做提取

第一個類型套路是模式匹配做提取。

模式匹配做提取的意思是通過類型 extends 一個模式類型,把需要提取的部分放到通過 infer 聲明的局部變量里。

舉個例子,用模式匹配提取函數參數類型。

typeGetParametersFunction>=
Funcextends(...args:inferArgs)=>unknown?Args:never;

typeParametersResult=GetParameters<(name:string,age:number)=>string>

首先用 extends 限制類型參數必須是 Function 類型。

然后用 extends 為 參數類型匹配公式,當滿足公式時,提取公式中的變量 Args。

實現函數參數類型的提取。

3.2 重新構造做變換

第二個類型套路是重新構造做變換。

重新構造做變換的意思是想要變化就需要重新構造新的類型,并且可以在構造新類型的過程中對原類型做一些過濾和變換。

比如實現一個字符串類型的重新構造。

typeCapitalizeStr=
Strextends`${inferFirst}${inferRest}`
?`${Uppercase}${Rest}`:Str;

typeCapitalizeResult=CapitalizeStr<'tang'>

首先限制參數類型必須是字符串類型。

然后用 extends 為參數類型匹配公式,提取公式中的變量 First Rest,并通過 Uppercase 封裝。

實現了首字母大寫的字符串字面量類型。

3.3 遞歸復用做循環

第三個類型套路是遞歸復用做循環。

TypeScript 本身不支持循環,但是可以通過遞歸完成不確定數量的類型編程,達到循環的效果。

比如通過遞歸實現數組類型反轉。

typeReverseArr=
Arrextends[inferFirst,...inferRest]
?[...ReverseArr,First]
:Arr;


typeReverseArrResult=ReverseArr<[1,2,3,4,5]>

首先限制參數必須是數組類型。

然后用 extends 匹配公式,如果滿足條件,則調用自身,否則直接返回。

實現了一個數組反轉類型。

3.4 數組長度做計數

第四個類型套路是數組長度做計數。

類型編程本身是不支持做加減乘除運算的,但是可以通過遞歸構造指定長度的數組,然后取數組長度的方式來完成數值的加減乘除。

比如通過數組長度實現類型編程的加法運算。

typeBuildArray<
????Length?extends?number,
????Ele?=?unknown,
????Arr?extends?unknown[]?=?[]
????>=Arr['length']extendsLength
?Arr
:BuildArray;

typeAdd=
[...BuildArray,...BuildArray]['length'];


typeAddResult=Add<32,25>

首先通過遞歸創建一個可以生成任意長度的數組類型

然后創建一個加法類型,通過數組的長度來實現加法運算。

三、類型體操實踐

分享的第三部分是類型體操實踐。

前面分享了類型體操的概念及常用的運算邏輯。

下面我們就用這些運算邏輯來解析 TypeScript 內置的高級類型。

1. 解析 TypeScript 內置高級類型

  • partial 把索引變為可選

通過 in 操作符遍歷索引,為所有索引添加 ?前綴實現把索引變為可選的新的映射類型。

typeTPartial={
[PinkeyofT]?:T[P];
};

typePartialRes=TPartial<{?name:'aa',age:18}>
  • Required 把索引變為必選

通過 in 操作符遍歷索引,為所有索引刪除 ?前綴實現把索引變為必選的新的映射類型。

typeTRequired={
[PinkeyofT]-?:T[P]
}

typeRequiredRes=TRequired<{?name?:?'aa',age?:18}>
  • Readonly 把索引變為只讀

通過 in 操作符遍歷索引,為所有索引添加 readonly 前綴實現把索引變為只讀的新的映射類型。

typeTReadonly={
readonly[PinkeyofT]:T[P]
}

typeReadonlyRes=TReadonly<{?name?:?'aa',age?:18}>
  • Pick 保留過濾索引

首先限制第二個參數必須是對象的 key 值,然后通過 in 操作符遍歷第二個參數,生成新的映射類型實現。

typeTPick={
[PinK]:T[P]
}

typePickRes=TPick<{?name?:?'aa',age?:18},'name'>
  • Record 創建映射類型

通過 in 操作符遍歷聯合類型 K,創建新的映射類型。

typeTRecord={
[PinK]:T
}

typeRecordRes=TRecord<'aa'|'bb',string>
  • Exclude 刪除聯合類型的一部分

通過 extends 操作符,判斷參數 1 能否賦值給參數 2,如果可以則返回 never,以此刪除聯合類型的一部分。

typeTExclude=TextendsU?never:T

typeExcludeRes=TExclude<'aa'|'bb','aa'>
  • Extract 保留聯合類型的一部分

和 Exclude 邏輯相反,判斷參數 1 能否賦值給參數 2,如果不可以則返回 never,以此保留聯合類型的一部分。

typeTExtract=TextendsU?T:never

typeExtractRes=TExtract<'aa'|'bb','aa'>
  • Omit 刪除過濾索引

通過高級類型 Pick、Exclude 組合,刪除過濾索引。

typeTOmit=Pick>

typeOmitRes=TOmit<{?name:'aa',age:18},'name'>
  • Awaited 用于獲取 Promise 的 valueType

通過遞歸來獲取未知層級的 Promise 的 value 類型。

typeTAwaited=
Textendsnull|undefined
?T
:Textendsobject&{then(onfulfilled:inferF):any}
?Fextends((value:inferV,...args:any)=>any)
?Awaited
:never
:T;


typeAwaitedRes=TAwaited<Promise<Promise<Promise>>>

還有非常多高級類型,實現思路和上面介紹的類型套路大多一致,這里不一一贅述。

2. 解析 ParseQueryString 復雜類型

重點解析的是在背景章節介紹類型體操復雜度,舉例說明的解析字符串參數的函數類型。

如圖示 demo 所示,這個函數是用于將指定字符串格式解析為對象格式。

functionparseQueryString1(queryStr){
if(!queryStr||!queryStr.length){
return{}
}
constqueryObj={}
constitems=queryStr.split('&')
items.forEach((item)=>{
const[key,value]=item.split('=')
if(queryObj[key]){
if(Array.isArray(queryObj[key])){
queryObj[key].push(value)
}else{
queryObj[key]=[queryObj[key],value]
}
}else{
queryObj[key]=value
}
})
returnqueryObj
}

比如獲取字符串 a=1&b=2 中 a 的值。

常用的類型聲明方式如下圖所示:

functionparseQueryString1(queryStr:string):Record<string,any>{
if(!queryStr||!queryStr.length){
return{}
}
constqueryObj={}
constitems=queryStr.split('&')
items.forEach((item)=>{
const[key,value]=item.split('=')
if(queryObj[key]){
if(Array.isArray(queryObj[key])){
queryObj[key].push(value)
}else{
queryObj[key]=[queryObj[key],value]
}
}else{
queryObj[key]=value
}
})
returnqueryObj
}

參數類型為 string,返回類型為 Record,這時看到,res1.a 類型為 any,那么有沒有辦法,準確的知道 a 的類型是字面量類型 1 呢?

下面就通過類型體操的方式,來重寫解析字符串參數的函數類型。

首先限制參數類型是 string 類型,然后為參數匹配公式 a&b,如果滿足公式,將 a 解析為 key value 的映射類型,將 b 遞歸 ParseQueryString 類型,繼續解析,直到不再滿足 a&b 公式。

最后,就可以得到一個精準的函數返回類型,res.a = 1

typeParseParam=
Paramextends`${inferKey}=${inferValue}`
?{
[KinKey]:Value
}:Record;

typeMergeParams<
????OneParam?extends?Record,
OtherParamextendsRecord
>={
readonly[KeyinkeyofOneParam|keyofOtherParam]:
KeyextendskeyofOneParam
?OneParam[Key]
:KeyextendskeyofOtherParam
?OtherParam[Key]
:never
}

typeParseQueryString=
Strextends`${inferParam}&${inferRest}`
?MergeParams,ParseQueryString>
:ParseParam;
functionparseQueryString<Strextendsstring>(queryStr:Str):ParseQueryString<Str>{
if(!queryStr||!queryStr.length){
return{}asany;
}
constqueryObj={}asany;
constitems=queryStr.split('&');
items.forEach(item=>{
const[key,value]=item.split('=');
if(queryObj[key]){
if(Array.isArray(queryObj[key])){
queryObj[key].push(value);
}else{
queryObj[key]=[queryObj[key],value]
}
}else{
queryObj[key]=value;
}
});
returnqueryObjasany;
}


constres=parseQueryString('a=1&b=2&c=3');

console.log(res.a)//type1

四、小結

綜上分享,從 3 個方面介紹了類型體操。

  • 第一點是類型體操背景,了解了什么是類型,什么是類型安全,怎么實現類型安全;

  • 第二點是熟悉類型體操的主要類型、支持的邏輯運算,并總結了 4 個類型套路;

  • 第三點是類型體操實踐,解析了 TypeScript 內置高級類型的實現,并手寫了一些復雜函數類型。

從中我們了解到需要動態生成類型的場景,必然是要用類型編程做一些運算,即使有的場景下可以不用類型編程,但是使用類型編程能夠有更精準的類型提示和檢查,減少代碼中潛在的問題。

審核編輯:湯梓紅


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3020

    瀏覽量

    74008
  • 編程
    +關注

    關注

    88

    文章

    3614

    瀏覽量

    93693

原文標題:類型體操的9種類型運算、4種類型套路總結

文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    詳細了解JTAG接口

    在FPGA研發及學習過程中,有個關鍵步驟就是下板實現,做硬件“硬現”很重要,般來說用JTAG口比較常見些,因此相信肯定有些大俠遇到過JTAG口失靈或者損壞無法使用的事情。最近我就遇到了這類事情
    發表于 07-20 09:15 ?1.2w次閱讀

    了解MyBatis的查詢原理

    可以詳細了解MyBatis的次查詢過程。在平時的代碼編寫中,發現了MyBatis個低版本的bug(3.4.5之前的版本),由于現在很多工程中的版本都是低于3.4.5的,因此在這里用
    的頭像 發表于 10-10 11:42 ?1424次閱讀

    用VDK+BF537開發產品中,想詳細了解下VDK中事件、事件bit、信號量的使用方法,以及如何寫自己的device drivers

    用VDK+BF537開發產品中,想詳細了解下VDK中事件、事件bit、信號量的使用方法,以及如何寫自己的device drivers。請問哪有針對上述問題的資料下載?
    發表于 12-06 09:19

    詳細了解下ups的相關計算

    關于ups方面的計算有很多,ups無論是接空開,還是連接電纜,以及選擇電池,都可能需要計算它的電流或功率等,那么今天我們來詳細了解下ups的相關計算。、UPS電源及電流、高頻ups與工頻ups
    發表于 11-16 09:08

    詳細了解下STM32F1的具體電路參數

    最近筆者在使用STM32時,需要詳細了解下F1的具體電路參數。于是查看其官方數據手冊,結果記錄如下。絕對最大額度值般工作條件表中的FT指5V 耐壓。可以在引腳定義表格中看到。I/O端口特性(邏輯電平)在最后
    發表于 01-18 07:07

    帶你詳細了解HarmonyOS折疊屏設計規范!

    /docs/design/des-guides/basic-requirements-0000001193421226),了解更多HarmonyOS折疊屏設計規范的詳細內容。
    發表于 05-20 10:22

    通過 iftop、 nethogs 和 vnstat 詳細了解你的網絡連接狀態

    通過 iftop、 nethogs 和 vnstat 詳細了解你的網絡連接狀態。
    的頭像 發表于 01-27 21:10 ?2.1w次閱讀
    通過 iftop、 nethogs 和 vnstat <b class='flag-5'>詳細了解</b>你的網絡連接狀態

    詳細了解HarmonyOS工程

    華為云享專家,InfoQ簽約作者,阿里云專家博主,51CTO博客首席體驗官,開源項目GVA成員之,專注于大前端技術的分享,包括Flutter,小程序,安卓,VUE,JavaScript。
    的頭像 發表于 02-28 10:53 ?1406次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>詳細了解</b>HarmonyOS工程

    詳細了解Cgroup

    cgroup最基本的操作時我們可以使用以下命令創建個cgroup文件夾
    的頭像 發表于 04-20 11:10 ?5866次閱讀

    詳細了解OpenHarmony新圖形框架

    3月30日,OpenHarmony v3.1 Release版本正式發布了。此版本為大家帶來了全新的圖形框架,實現了UI框架顯示、多窗口、流暢動畫等基礎能力,夯實了OpenHarmony系統能力基座。下面就帶大家詳細了解新圖形框架。
    的頭像 發表于 04-27 13:21 ?2210次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>詳細了解</b>OpenHarmony新圖形框架

    詳細了解HTTP協議

    Http協議即超文本傳送協議 (HTTP-Hypertext transfer protocol) 。
    的頭像 發表于 05-11 12:04 ?1700次閱讀

    詳細了解交換機數據接口類型

    交換機的接口類型變得非常豐富,為了讓大家對這些接口有個比較清晰的認識今天我們就聊下交換機數據接口類型,方便大家選擇。
    發表于 06-21 14:51 ?2638次閱讀

    詳細了解CCIX規范

    正文開始前,閑扯幾句。在接下來分析CCIX規范的過程中,大家會發現CCIX里面有太多ARM的影子,尤其是協議層的致性協議部分,你會看到有很多跟CHI相似的東西。另外,在CCIX規范的底層,基本全是復用和遵循PCIe規范。
    的頭像 發表于 06-23 09:20 ?2031次閱讀

    帶您詳細了解IEEE802.3bt(PoE++)的有關特點

    Hqst華強盛(盈盛電子)導讀:帶您詳細了解IEEE802.3bt(PoE++)的有關特點,讓我們對IEEE802.3bt(PoE++)協議有更具體的了解
    的頭像 發表于 01-04 11:26 ?2159次閱讀
    帶您<b class='flag-5'>一</b>起<b class='flag-5'>詳細了解</b>IEEE802.3bt(PoE++)的有關特點

    帶你詳細了解工業電腦

    扇設計、承受振動和惡劣環境的能力、輕松配置、全面的I/O選項、延長生命周期、耐用的組件。了解如何為您的應用選擇工業電腦對提高設施的生產力和效率至關重要。詳細了解
    的頭像 發表于 06-12 14:24 ?401次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b>帶你<b class='flag-5'>詳細了解</b>工業電腦
    主站蜘蛛池模板: 怡春院欧美一区二区三区免费| 蜜桃无码AV视频在线观看| 大陆午夜伦理| xnxnxn69日本| GOGOGO高清在线播放免费| 95国产精品人妻无码久| 中文字幕在线不卡精品视频99| 亚洲免费观看| 亚洲欧洲精品A片久久99| 亚洲高清视频免费| 最近日本字幕MV免费观看在线| 一区二区三区福利视频| 依人青青青在线观看| 中文字幕 日韩 无码 在线| 中文字幕人成人乱码亚洲影视| 在线观看免费视频a| 18av 在线| 99国产精品人妻无码免费| 99人精品福利在线观看| xxx日本高清视频hd| 成人在线免费看片| 国产成人精品男人的天堂网站| 国产 日韩 欧美 高清 亚洲| 国产精品久久久久久久A片冻果| 国产精品你懂得| 国内精自品线一区91| 久久国产露脸老熟女熟69| 绿巨人www| 人妻天天爽夜夜爽三区麻豆A片| 日日夜夜操操操| 亚洲成人免费观看| 依人在线观看| WWW亚洲精品久久久无码| 高挑人妻无奈张开腿| 国产亚洲视频精彩在线播放| 久久re热在线视频精69| 男女免费观看在线爽爽爽视频 | 9亚洲欧洲免费无码在线| 超碰免费视频caopoom9| 国产精品久久一区二区三区蜜桃| 国内精品久久久久影院老司|