<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
TypeScript 的型別系統,最基本的是簡單對應 JavaScript 的 基本型別,比如 string、number、boolean 等,然後是新增的 tuple、enum、複合型別、交叉型別、索引型別等 增強型別。
這裡會有一個問題,就是函數宣告支援不同型別的重複編寫問題,比如我的一個函數要接收一個陣列,然後從中取中一個元素。
一旦我們傳入的陣列型別不同,都要寫多一個 type 別名,未免太繁瑣。
type getStrItem = (items: string[]) => string; type getNumItem = (items: number[]) => number; // ... 每增加一種型別都要寫多了一個 type 別名 const getStrFirst: getStrItem = (a) => { return a[0]; }
為解決這個問題,TypeScript 引入了 泛型,讓型別也能成為引數了。
type getItem<T> = (items: T[]) => T const getStrFirst: getItem<string> = (a) => { return a[0]; }
上面的 T 就是一個型別引數,當我們通過 型別別名<具體型別>
形式(上面程式碼對應 getItem<string>
),我們就能得到一個具體的型別了。
鑑於 JavaScript 太靈活,TypeScript 實現的是結構型別系統,我們又覺得泛型的簡單推到 T 的粒度還是不夠細,我們希望能夠獲取 T 內部的結構。
於是,TypeScript 在泛型的基礎上,又提供了 型別程式設計,通過一些語法,我們可以拿到 T 下更細粒度的型別,或通過判斷拿到其他型別。
這個也被大家戲稱為 型別體操。可能是因為實現起來花裡胡哨像是在參加體操大賽的原因。
總結一下,從型別能力上的增強的過程來說,就是:
基本型別 -> 泛型 -> 型別程式設計(型別體操)
TS 程式碼版本為 4.8.2
下面我們來看一下 TypeScript 內建的幾個高階型別,它們用了型別程式設計。
Pick<Type, Keys>
Pick 的作用是,從 T 型別(物件型別)中,提取出 K(聯合型別)圈定的 key,返回一個新的物件型別。
這裡我們通過 Pick 提取了需要的 pos 和 radius 物理資訊屬性。
看看 Pick 的實現:
/** * From T, pick a set of properties whose keys are in the union K */ type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
首先我們看等號左側的 <T, K extends keyof T>
,型別引數有兩個,T 和 K。
先說型別引數命名。
型別變數命名和寫 JS 變數一樣,隨意起名。但建議首字母大寫,以防止和一些關鍵字混淆(比如 extends, as, infer),這些關鍵詞都是小寫的。
T 通常代表一個要被分析的型別(Type),K 通常代表物件屬性名(Key)。就像數學中函數的 x 和 y 一樣,想不到好的命名就用這倆。
keyof 是型別運運算元,用於提取物件的屬性(key),然後拼裝成聯合型別。
extends 用於限制型別引數的範圍。比如 <T extends string>
表示 T 型別必須是 string 的子類,像字面量的 "a" 或 string 都是 string 的子類。如果不是 string 子類,編譯無法通過。
還有一種是 extends ? : 的類似 JS 中三元運運算元的語法,它在等號的右側,用於實現條件判斷。它和前面提到的 extends 不是同一樣東西,後面我會說到。
Ok,我們整體看看 <T, K extends keyof T>
代表什麼意思。它表示傳入 T 和 K 兩個型別引數,然後 K 必須是 T 的屬性組成的聯合型別中的一部分。
我們再看看等號右邊 { [P in K]: T[P]; };
,它是對型別進行 重對映。
in 用於對聯合型別進行遍歷。也就是遍歷我們需要用到的 key,作為索引 P,然後它的值還是用對應的 T[P]。
Exclude 的作用是,從聯合型別中剔除掉一些型別。
實現如下:
/** * Exclude from T those types that are assignable to U */ type Exclude<T, U> = T extends U ? never : T;
這裡涉及到一個經常用到的 條件語法:extends ? :
,你可以把它類比為 JS 中的三元表示式(即 condition ? a : b
)。
為了更好的講解,我們實現一個型別 IsNumber,判斷一個型別是否為數值型別。
type IsNumber<T> = T extends number ? true : false; // 使用 type A = IsNumber<1> // true type B = IsNumber<"str"> // false
T extends number
判斷 T 是否為 number 的子類,如果是的話,返回 true,否則返回 false。
需注意和前面的型別引數上 extends 是完全不同的東西。
回到我們的 Exclude,邏輯就很清楚了,就是判斷 T 是否為 U 的子類,如果是的話,返回 never(效果是被丟棄);否則返回 T。
你是不是有點奇怪結果,邏輯看起來不應該是 "a" | "b" | "c" 不是 "b" 的子類,返回 "a" | "b" | "c" 嗎?怎麼程式設計了 "a" | "c"?
其實這是聯合型別的特殊邏輯,如果聯合型別使用了 extends,它就會被打散,變成多個獨立的型別進行判斷,最後再組合起來。
所以真正邏輯是, "a" | "b" | "c" 被打散,變成依次判斷 "a" 、"b"、"c" 是否為 "b" 的子類,分別得到 "a" 、never、"c",然後聯合起來,就變成了 "a" | "c"。
獲取函數型別的返回值型別。
實現為:
/** * Obtain the return type of a function type */ type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
等號左側的 (...args: any) => any
代表一個任意函數型別,用於限制傳入引數的型別。
然後我們看到了一個新的關鍵詞 infer,代表參照的意思,用於型別推導。
extends 和 infer 搭配,可以實現 模式匹配,如果 extends 匹配成功,infer 就能推導獲得對應的型別。
如果你瞭解 JS 的正規表示式,你會發現它們很像,infer 好比是捕獲組。
'ABC'.replace(/A(.)C/, '$1') // 'B'。提取了模式上匹配的一個字串
在 T extends (...args: any) => infer R ? R : any;
中,我們給返回值部分設定了 infer,並提供了一個區域性變數 R。
如果 extends 條件判斷是繼承關係,那麼變數 R 就會被賦值函數的返回值。
後面的判斷為真的分支(? 後面的表示式)就能拿到這個 R。判斷為假的分支就無法拿到,因為匹配失敗了。
這個 extends + infer 其實就是型別體操的精髓,可以在傳入型別 T 繼續拆分,拿到更細粒度的型別。
還有更多的型別程式設計的技巧因為篇幅原因就不說了,比如還有:
TypeScript 的型別是圖靈完備的,可以實現各種判斷、迴圈、加減的邏輯。當然某些邏輯實現起來很繁瑣就是了。
它的語法也是與眾不同:它做了 “壓縮”。一個型別的程式設計只是一個表示式,需要用 extend ? : 的方式不停巢狀實現邏輯。TS 型別體操學起來,某種意義上確實有點像學一門新的語言,而且有那麼一點古怪。
以上就是TypeScript 內建高階型別程式設計範例的詳細內容,更多關於TypeScript 內建型別的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45