成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

真實案例說明 TypeScript 類型體操的意義

開發 前端
類型編程可以通過類型運算產生更準確的類型,配合編輯器可以做更精準的類型提示和檢查,這就是類型體操的意義。

TypeScript 類型系統支持類型編程,也就是對類型參數做一系列運算產生新的類型。比如這樣:

type isTwo<T> = T extends 2 ? true: false;

這種類型編程邏輯可以寫的很復雜,所以被戲稱為“類型體操”。

它是 TS 中最強大也是最復雜的部分了,屬于深水區的內容。

很多同學不知道類型編程學了有什么用,好像做業務也用不到這個。那今天我們就來看一個具體的例子,來感受下類型體操的意義。

我們想實現這樣一個 JS 方法:

function parseQueryString(queryStr) {
if (!queryStr || !queryStr.length) {
return {};
}
const queryObj = {};
const items = 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;
}
});
return queryObj;
}

這段代碼很容易看出來就是做 query string 的 parse 的,會把 'a=1&b=2&c=3' 的字符串 parse 成 { a: 1, b: 2, c: 3 } 返回。如果有同名的 key 的話,就合并到一個數組里。

JS 的邏輯大家寫的比較多,這部分很容易理解:

那如果要給這個函數加上類型,大家會怎么加呢?

我猜,大部分人會這么加:

參數是 string 類型,返回值是 parse 之后的對象類型 object。

這樣是可以的,而且 object 還可以寫成 Record,因為對象是索引類型(索引類型就是聚合多個元素的類型,比如對象、class、數組都是)。

Record 是 TS 內置的一個高級類型,是通過映射類型的語法來生成索引類型的:

type Record = { [P in K]: T;}

比如傳入 'a' | 'b' 作為 key,1 作為 value,就可以生成這樣索引類型:

所以這里的 Record 也就是 key 為 string 類型,value 為任意類型的索引類型,可以代替 object 來用,更加語義化一點:

但是不管是返回值類型為 object 還是 Record 都存在一個問題:返回的對象不能提示出有哪些屬性:

對于習慣了 ts 的提示的同學來說,沒有提示太不爽了。怎么能讓這個函數的返回的類型有提示呢?

這就要用到類型編程了。

我們把函數的類型定義改成這樣:

聲明一個類型參數 Str,約束為 string 類型,函數參數的類型指定是這個 Str,返回值的類型通過對 Str 做類型運算得到,也就是 ParseQueryString。

這個 ParseQueryString 的類型做的事情就是把傳入的 Str 通過各種類型運算產生對應的索引類型。

這樣返回的類型就有提示了:

是不是很神奇!這就是類型體操的魅力!能夠實現更精準的類型提示。

那這個 ParseQueryString 的高級類型是怎么實現的呢?

其實我們實現過:??TS 類型體操:圖解一個復雜高級類型??,這里再講一下:

首先我們要把 'a=1&b=2&c=3' 的字符串按照 & 分割開,使用模式匹配的方式。

把提取出來的每一個 a=1、b=2、c=3 這種字符串再做一次處理,把結果合并起來返回。

也就是:

type ParseQueryString<Str extends string>
= Str extends `${infer Param}&${infer Rest}`
? MergeParams<ParseParam<Param>, ParseQueryString<Rest>>
: ParseParam<Str>;

類型參數 Str 為待處理的字符串類型,通過模式匹配的方式提取 & 分割的字符串到 infer 聲明的局部變量 Param 中,剩下的放到 infer 聲明的局部變量 Rest 中。

對提取出來的 Param 再做處理,也就是 ParseParam,剩下的遞歸處理,也就是 ParseQueryString,然后把結果合并。

如果模式匹配不滿足,就說明沒有 & 了,那就把剩下的也做一次處理返回。

這里的 ParseParam 就是處理 a=1、b=2、c=3 這種字符串的,也是通過模式匹配來提取:

type ParseParam<Param extends string> = 
Param extends `${infer Key}=${infer Value}`
? {
[K in Key]: Value
} : Record<string, any>;

類型參數 Param 是待處理的字符串,通過模式匹配提取 = 分隔的字符串到局部變量 Key 和 Value 中,構造成索引類型返回;

如果模式匹配不滿足,說明不是 = 分隔的字符串字面量類型,就返回 Record 代表任意索引類型。

測試下:

然后對多個索引類型的合并,就是通過映射類型的語法構造一個新的索引類型:

type MergeParams<
OneParam extends Record<string, any>,
OtherParam extends Record<string, any>
> = {
readonly [Key in keyof OneParam | keyof OtherParam]:
Key extends keyof OneParam
? Key extends keyof OtherParam
? MergeValues<OneParam[Key], OtherParam[Key]>
: OneParam[Key]
: Key extends keyof OtherParam
? OtherParam[Key]
: never
}

類型參數 OneParam 和 OtherParam 是兩個索引類型,通過 Record 來約束。

通過映射類型的語法構造一個新的索引類型返回,Key 來自兩者的合并,也就是 Key in keyof OneParam | keyof OtherParam。并且加上一個 readonly 的修飾,這樣就是讓返回的索引類型不能被修改。

值要判斷下如果是兩者都有的值,那就做合并,否則分別取對應的值。

合并的邏輯是這樣的:

type MergeValues<One, Other> = 
One extends Other
? One
: Other extends unknown[]
? [One, ...Other]
: [One, Other];

類型參數 One、Other 為待合并的兩個值的類型,如果兩個一樣就返回其中一個,否則如果是數組就合并數組,也就是 [One, ...Other],否則把兩個值合并成數組 [One, Other]。

這樣就完成了兩個索引類型的合并,測試下:

整體測試下:

成功了!我們實現了 ParseQueryString 的高級類型!(如果對類型體操看不明白的話,可以去看下我的小冊《TypeScript 類型體操通關秘籍》補下基礎)。

當然,這只是純粹的類型體操,把它用到 JS 里才是最終目的,所以我們把 parseQueryString 的類型定義改成了這樣:

把函數參數的類型傳入 ParseQueryString 的高級類型做類型運算,返回的結果作為函數返回值的類型。(這里要用 as any 把返回值斷言為 any,因為默認推導的類型不精確,我們用根據 Str 動態算出來的類型)

這樣也就能實現精準的類型提示:

并且因為我們 readonly 的限制,不能修改屬性的值:

對比下沒用類型體操的時候:

就可以得出結論:

類型編程可以通過類型運算產生更準確的類型,配合編輯器可以做更精準的類型提示和檢查,這就是類型體操的意義。

總結

類型編程是 TypeScript 的深水區內容,它是對類型做一系列類型運算后產生新的類型,它可以實現更精準的類型提示和檢查。

我們通過 parseQueryString 這個函數的類型定義來直觀感受了下用類型體操和不用類型體操的區別,在類型提示這方面,體驗是相差很多的。

實現更精準的類型提示和檢查,這就是類型體操的意義!

責任編輯:武曉燕 來源: 神光的編程秘籍
相關推薦

2022-09-20 14:43:55

TypeScript類型體操

2021-12-10 08:21:15

TypeScript高級類型類型體操

2020-12-29 07:15:34

TypeScript語言代碼

2025-04-10 05:00:00

JavaScriptReactWeb

2023-03-30 07:55:02

2022-02-09 08:11:50

架構

2019-03-22 13:46:13

公共云云計算云端

2021-07-27 06:06:34

TypeScript語言運算符

2022-02-25 09:06:02

TypeScripnever工具

2024-02-27 13:07:49

用戶畫像數據分析HR

2022-08-08 09:00:42

TypeScript映射類型

2024-05-11 10:19:31

TypeScript類型接口

2022-04-11 08:42:09

TypeScript子類型定義

2021-08-18 07:56:05

Typescript類型本質

2025-02-14 08:26:47

TypeScripDeepSeek

2010-10-09 10:39:45

2010-08-30 17:52:31

Windows Azu云計算數據中心

2024-02-19 10:24:32

Chainable工具類型類型體操

2024-03-04 06:40:49

工具類型TypeScripDeepPick

2022-01-19 23:41:56

TS索引類型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人日批视频 | 国产精品美女一区二区三区 | 午夜网| 国产精品一区视频 | 综合天天久久 | h视频在线免费 | chinese中国真实乱对白 | 北条麻妃一区二区三区在线观看 | 国产做a爱片久久毛片 | 极品久久 | 黄色小视频入口 | 国产情侣激情 | 91免费版在线观看 | 国产午夜精品一区二区三区四区 | 国产伦精品一区二区三区高清 | 久久精品二区亚洲w码 | 久草在线高清 | 久久久久久免费免费 | 国产精品乱码一区二三区小蝌蚪 | 操人网站| 中文字幕视频一区 | 99久久99热这里只有精品 | 久久久久国产精品 | 日韩亚洲欧美综合 | 一区二区三区高清在线观看 | 欧美精品一区二区三区蜜臀 | 日韩欧美三级电影 | 欧美日韩视频在线 | 久久99精品久久久 | 特一级毛片 | 亚洲欧美中文日韩在线 | av中文字幕网 | 国产精品污www一区二区三区 | 亚洲国产高清高潮精品美女 | 国产精品jizz在线观看老狼 | 日韩欧美国产一区二区三区 | 久久这里只有精品首页 | 久久精品国产99国产精品亚洲 | 91素人 | 99热在这里只有精品 | 天天澡天天狠天天天做 |