TypeScript 高級類型 - 可辨識聯合

首先先來描述一個需求場景,例若有一個建立用戶和更新用戶的功能,其中要傳給服務端的字段除了「更新」須要多一個「id」屬性之外其他屬性都同樣。typescript

在此我先定義一個接口來聲明這個參數對象的類型:函數

interface Prop{
    action:'create'|'update';
    id?:string;
    name:string;
}
複製代碼

可是咱們發現,這個接口並不知足咱們的需求,由於咱們這樣建立對象依然會經過:ui

const a:Prop = {
    action:'create',
    id:'1',
    name:'zhangsan'
}
複製代碼

這個類型並不會經過 action 的值來幫我判斷是否應該有 id 字段。spa

接下來換個寫法來改進一下:code

type Prop =
  | {
      action: "create";
      name: string;
    }
  | {
      action: "update";
      id: string;
      name: string;
    };

const a: Prop = {
  action: "update",
  name: "zhangsan"
};
複製代碼

這時若是咱們聲明一個 Prop 類型的變量沒有 id 屬性,TypeScript 就會報出異常:對象

Property 'id' is missing in type '{ action: "update"; name: string; }' but required in type '{ action: "update"; id: string; name: string; }'.接口

這就順利解決了咱們的問題,可是接着又遇到一個問題,當我在一個函數中傳入 Prop 類型的參數,並使用了它的 id 屬性時,TypeScript 又報了一個錯誤:ip

type Prop =
  | {
      action: "create";
      name: string;
    }
  | {
      action: "update";
      id: string;
      name: string;
    };

function fn(e: Prop) {
  console.log(e.id);
}
// Property 'id' does not exist on type '{ action: "create"; name: string; }'.
複製代碼

原來是 TypeScript 並不肯定你傳進來的對象的 actionupdate 仍是 create,因此繼續改進一些代碼來幫助 TypeScript 判斷:string

type Prop =
  | {
      action: "create";
      name: string;
    }
  | {
      action: "update";
      id: string;
      name: string;
    };

function fn(e: Prop) {
  if (e.action === "create") {
    console.log(e.name);
  } else {
    console.log(e.id);
  }
}
複製代碼

這樣報錯就順利解決了。it

咱們一直在使用的 type Prop 這個類型就是一個可辨識聯合,從上面的代碼來看它有如下特色:

  1. 一個共有的字段。在上文中這個共有字段是 action
  2. 這個共有字段的值是可窮舉的。由於若是值是不可窮舉的,就沒法用選擇語句來對變量的具體類型進行判斷。
相關文章
相關標籤/搜索