面試官:說說你對 TypeScript 中高級類型的理解?有哪些?
本文轉(zhuǎn)載自微信公眾號「JS每日一題」,作者 灰灰。轉(zhuǎn)載本文請聯(lián)系JS每日一題公眾號。
一、是什么
除了string、number、boolean 這種基礎(chǔ)類型外,在 typescript 類型聲明中還存在一些高級的類型應(yīng)用
這些高級類型,是typescript為了保證語言的靈活性,所使用的一些語言特性。這些特性有助于我們應(yīng)對復(fù)雜多變的開發(fā)場景
二、有哪些
常見的高級類型有如下:
- 交叉類型
 - 聯(lián)合類型
 - 類型別名
 - 類型索引
 - 類型約束
 - 映射類型
 - 條件類型
 
交叉類型
通過 & 將多個類型合并為一個類型,包含了所需的所有類型的特性,本質(zhì)上是一種并的操作
語法如下:
- T & U
 
適用于對象合并場景,如下將聲明一個函數(shù),將兩個對象合并成一個對象并返回:
- function extend<T , U>(first: T, second: U) : T & U {
 - let result: <T & U> = {}
 - for (let key in first) {
 - result[key] = first[key]
 - }
 - for (let key in second) {
 - if(!result.hasOwnProperty(key)) {
 - result[key] = second[key]
 - }
 - }
 - return result
 - }
 
聯(lián)合類型
聯(lián)合類型的語法規(guī)則和邏輯 “或” 的符號一致,表示其類型為連接的多個類型中的任意一個,本質(zhì)上是一個交的關(guān)系
語法如下:
- T | U
 
例如 number | string | boolean 的類型只能是這三個的一種,不能共存
如下所示:
- function formatCommandline(command: string[] | string) {
 - let line = '';
 - if (typeof command === 'string') {
 - line = command.trim();
 - } else {
 - line = command.join(' ').trim();
 - }
 - }
 
類型別名
類型別名會給一個類型起個新名字,類型別名有時和接口很像,但是可以作用于原始值、聯(lián)合類型、元組以及其它任何你需要手寫的類型
可以使用 type SomeName = someValidTypeAnnotation的語法來創(chuàng)建類型別名:
- type some = boolean | string
 - const b: some = true // ok
 - const c: some = 'hello' // ok
 - const d: some = 123 // 不能將類型“123”分配給類型“some”
 
此外類型別名可以是泛型:
- type Container<T> = { value: T };
 
也可以使用類型別名來在屬性里引用自己:
- type Tree<T> = {
 - value: T;
 - left: Tree<T>;
 - right: Tree<T>;
 - }
 
可以看到,類型別名和接口使用十分相似,都可以描述一個對象或者函數(shù)
兩者最大的區(qū)別在于,interface只能用于定義對象類型,而 type 的聲明方式除了對象之外還可以定義交叉、聯(lián)合、原始類型等,類型聲明的方式適用范圍顯然更加廣泛
類型索引
keyof 類似于 Object.keys ,用于獲取一個接口中 Key 的聯(lián)合類型。
- interface Button {
 - type: string
 - text: string
 - }
 - type ButtonKeys = keyof Button
 - // 等效于
 - type ButtonKeys = "type" | "text"
 
類型約束
通過關(guān)鍵字 extend 進(jìn)行約束,不同于在 class 后使用 extends 的繼承作用,泛型內(nèi)使用的主要作用是對泛型加以約束
- type BaseType = string | number | boolean
 - // 這里表示 copy 的參數(shù)
 - // 只能是字符串、數(shù)字、布爾這幾種基礎(chǔ)類型
 - function copy<T extends BaseType>(arg: T): T {
 - return arg
 - }
 
類型約束通常和類型索引一起使用,例如我們有一個方法專門用來獲取對象的值,但是這個對象并不確定,我們就可以使用 extends 和 keyof 進(jìn)行約束。
- function getValue<T, K extends keyof T>(obj: T, key: K) {
 - return obj[key]
 - }
 - const obj = { a: 1 }
 - const a = getValue(obj, 'a')
 
映射類型
通過 in 關(guān)鍵字做類型的映射,遍歷已有接口的 key 或者是遍歷聯(lián)合類型,如下例子:
- type Readonly<T> = {
 - readonly [P in keyof T]: T[P];
 - };
 - interface Obj {
 - a: string
 - b: string
 - }
 - type ReadOnlyObj = Readonly<Obj>
 
上述的結(jié)構(gòu),可以分成這些步驟:
- keyof T:通過類型索引 keyof 的得到聯(lián)合類型 'a' | 'b'
 - P in keyof T 等同于 p in 'a' | 'b',相當(dāng)于執(zhí)行了一次 forEach 的邏輯,遍歷 'a' | 'b'
 
所以最終ReadOnlyObj的接口為下述:
- interface ReadOnlyObj {
 - readonly a: string;
 - readonly b: string;
 - }
 
條件類型
條件類型的語法規(guī)則和三元表達(dá)式一致,經(jīng)常用于一些類型不確定的情況。
- T extends U ? X : Y
 
上面的意思就是,如果 T 是 U 的子集,就是類型 X,否則為類型 Y
三、總結(jié)
可以看到,如果只是掌握了 typeScript 的一些基礎(chǔ)類型,可能很難游刃有余的去使用 typeScript,需要了解一些typescript的高階用法,在實(shí)踐場景中,還有更多更復(fù)雜的組合,需要在實(shí)踐中慢慢體會
參考文獻(xiàn)
https://www.tslang.cn/docs/handbook/advanced-types.html
https://juejin.cn/post/6844904003604578312
https://zhuanlan.zhihu.com/p/103846208
















 
 
 



 
 
 
 