TS 其他類型的介紹與使用

二、高級類型

交叉類型, 聯合類型, 類型別名, 類型索引, 類型約束, 映射類型, 條件類型

交叉類型

通過 & 將多個類型合併爲一個類型,包含了所需的所有類型的特性,本質上是一種並的操作

K & Y

適用於對象合併場景,如下將聲明一個函數,將兩個對象合併成一個對象並返回:

function assign<K , Y>(one: K, two: Y) : K & Y {
    let res: <K & Y> = {}
    for (let key in one) {
        res[key] = one[key]
    }
    for (let key in two) {
        if(!res.hasOwnProperty(key)) {
            res[key] = two[key]
        }
    }
    return res
}

聯合類型

聯合類型的語法規則和邏輯 “或” 的符號一致,表示其類型爲連接的多個類型中的任意一個,本質上是一個交的關係

T | U

例如 number | string | boolean 的類型只能是這三個的一種,不能共存

如下所示:

function formatCommandline(command: string[] | string) {
  let line = '';
  if (typeof command === 'string') {
    line = command.trim();
  } else {
    line = command.join(' ').trim();
  }
}

類型別名

類型別名會給一個類型起個新名字,類型別名有時和接口很像,但是可以作用於原始值、聯合類型、元組以及其它任何你需要手寫的類型

可以使用 type SomeName = someValidTypeAnnotation 的語法來創建類型別名:

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>;
}

可以看到,類型別名和接口使用十分相似,都可以描述一個對象或者函數

兩者最大的區別在於,interface 只能用於定義對象類型,而 type 的聲明方式除了對象之外還可以定義交叉、聯合、原始類型等,類型聲明的方式適用範圍顯然更加廣泛

類型索引

keyof 類似於 Object.keys ,用於獲取一個接口中 Key 的聯合類型。

interface Ayong {
    name: string
    age: Number
}
const ayong={name:'ayong',age:18}
//這樣寫可以確定 key 的數據類型只能 是 Ayong類型中的
function getValue(key:keyof Ayong){
  return ayong[key]
}

類型約束

通過關鍵字 extend 進行約束,不同於在 class 後使用 extends 的繼承作用,泛型內使用的主要作用是對泛型加以約束

Even 對象實例返回值類型 肯定是 Event, 但是我們想給 ev 添加屬性怎麼做?

以上寫法必然會報錯

我可以這樣做

 interface Evt extends Event {//繼承基礎Event事件對象
  name?: Sring;
}
function diyEvent(){
  const evt :Evt = new Event('自定義事件')
  evt.name = 'ayong'
}

類型約束通常和類型索引一起使用,例如我們有一個方法專門用來獲取對象的值,但是這個對象並不確定,我們就可以使用 extends 和 keyof 進行約束。

function getValue<T, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}
const obj = { name: '阿勇' }
const name = getValue(obj, 'name')

以下是企業級項目中對 dom.addEventListener 事件監聽方法做了個上層封裝, 實際寫法如下

/**
 * @param {Object} element Dom 節點 HTMLPictureElement
 * @param {String} eventType 事件類型
 * @param {Funtion} complete (e) 方法回掉
 * @param {Boolean} useCapture true 冒泡觸發回掉 ,false冒泡觸發回掉
 */
function addEventListener<T extends EventTarget, E extends  Event>({
  element,
  type,
  handler
}: {
  element: T;
  type: string;
  handler: (this: T, evt: E) => void;
}) {
  element.addEventListener(type, handler as (evt: Event) => void);
}

映射類型

通過 in 關鍵字做類型的映射,遍歷已有接口的 key 或者是遍歷聯合類型,如下例子:

// 類型 ProKeys 有x/y/z,另一個類型Type1中也有x/y/z,並且Type1中的x/y/z類型相同
type ProKeys = 'x' | 'y' | 'z';
// 現在這種書寫方式相當於x/y/z重複書寫了兩次。
type Type1 = {x: number; y:number; z:number}

我們可以這樣做

type ProKeys = 'x' | 'y' | 'z';
type Type2 = {[Key in ProKeys]:number}
//映射類型相當於 一個類型枚遍歷舉 進行一一對應

條件類型

條件類型的語法規則和三元表達式一致,經常用於一些類型不確定的情況。

K extends T ? H : N

上面的意思就是,如果 K 是 T 的子集,就是類型 H,否則爲類型 N

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/5tflNaK2BpEKIll7j2ZydQ