欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解TypeScript2.0標(biāo)記聯(lián)合類型

 更新時(shí)間:2021年05月07日 10:36:23   作者:淺笑·  
這篇文章主要介紹了TypeScript2.0標(biāo)記聯(lián)合類型,對(duì)TS感興趣的同學(xué),可以參考下

使用標(biāo)記的聯(lián)合類型構(gòu)建付款方式

假設(shè)咱們?yōu)橄到y(tǒng)用戶可以選擇的以下支付方式建模

  • Cash (現(xiàn)金)
  • PayPal 與給定的電子郵件地址
  • Credit card 帶有給定卡號(hào)和安全碼

對(duì)于這些支付方法,咱們可以創(chuàng)建一個(gè) TypeScript 接口

interface Cash {
  kind: "cash";
}

interface PayPal {
  kind: "paypal",
  email: string;
}

interface CreditCard {
  kind: "credit";
  cardNumber: string;
  securityCode: string;
}

注意,除了必需的信息外,每種類型都有一個(gè)kind屬性,即所謂的判別屬性。這里每種情況都是字符串字面量類型。

現(xiàn)在定義一個(gè)PaymentMethod類型,它是我們剛才定義的三種類型的并集。通過這種方式,用聲明PaymentMethod每個(gè)變量, 必須具有給定的三種組成類型中的一種:

type PaymentMethod = Cash | PayPal | CreditCard;

現(xiàn)在我們的類型已經(jīng)就緒,來(lái)編寫一個(gè)函數(shù)來(lái)接受付款方法并返回一個(gè)讀得懂的話語(yǔ):

function describePaymentMethod(method: PaymentMethod) {
  switch (method.kind) {
    case "cash":
      // Here, method has type Cash
      return "Cash";

    case "paypal":
      // Here, method has type PayPal
      return `PayPal (${method.email})`;

    case "credit":
      // Here, method has type CreditCard
      return `Credit card (${method.cardNumber})`;
  }
}

首先,該函數(shù)包含的類型注釋很少,method參數(shù)僅包含一個(gè)。除此之外,函數(shù)基本是純 ES2015代碼。

在switch語(yǔ)句的每個(gè)case中,TypeScript 編譯器將聯(lián)合類型縮小到它的一個(gè)成員類型。例如,當(dāng)匹配到"paypal",method參數(shù)的類型從PaymentMethod縮小到PayPal。因此,咱們可以訪問email屬性,而不必添加類型斷言。

本質(zhì)上,編譯器跟蹤程序控制流以縮小標(biāo)記聯(lián)合類型。除了switch語(yǔ)句之外,它還要考慮條件以及賦值和返回的影響。

function describePaymentMethod(method: PaymentMethod) {
  if (method.kind === "cash") {
    // Here, method has type Cash
    return "Cash";
  }

  // Here, method has type PayPal | CreditCard

  if (method.kind === "paypal") {
    // Here, method has type PayPal
    return `PayPal (${method.email})`;
  }

  // Here, method has type CreditCard
  return `Credit card (${method.cardNumber})`;
}

控制流的類型分析使得使用標(biāo)記聯(lián)合類型非常順利。使用最少的 TypeScript語(yǔ)法開銷,咱可以編寫幾乎純js,并且仍然可以從類型檢查和代碼完成中受益。

使用標(biāo)記聯(lián)合類型構(gòu)建 Redux 操作

標(biāo)記聯(lián)合類型真正發(fā)揮作用的用例是在 TypeScript 應(yīng)用程序中使用Redux時(shí)。 編寫一個(gè)事例,其中包括一個(gè)模型,兩個(gè)actions和一個(gè)Todo應(yīng)用程序的reducer。

以下是一個(gè)簡(jiǎn)化的Todo類型,它表示單個(gè)todo。這里使用readonly修飾符為了防止屬性被修改。

interface Todo {
  readonly text: string;
  readonly done: boolean;
}

用戶可以添加新的 todos 并切換現(xiàn)有 todos 的完成狀態(tài)。根據(jù)這些需求,咱們需要兩個(gè)Redux操作,如下所示:

interface AddTodo {
  type: "ADD_TODO";
  text: string;
}

interface ToggleTodo {
  type: "TOGGLE_TODO";
  index: number
}

與前面的示例一樣,現(xiàn)在可以將Redux操作構(gòu)建為應(yīng)用程序支持的所有操作的聯(lián)合

type ReduxAction = AddTodo | ToggleTodo;

在本例中,type屬性充當(dāng)判別屬性,并遵循Redux中常見的命名模式?,F(xiàn)在添加一個(gè)與這兩個(gè)action一起工作的Reducer:

function todosReducer(
  state: ReadonlyArray<Todo> = [],
  action: ReduxAction
): ReadonlyArray<Todo> {
  switch (action.type) {
    case "ADD_TODO":
      // action has type AddTodo here
      return [...state, { text: action.text, done: false }];

    case "TOGGLE_TODO":
      // action has type ToggleTodo here
      return state.map((todo, index) => {
        if (index !== action.index) {
          return todo;
        }

        return {
          text: todo.text,
          done: !todo.done
        };
      });

    default:
      return state;
  }
}

同樣,只有函數(shù)簽名包含類型注釋。代碼的其余部分是純 ES2015,而不是特定于 TypeScript。

我們遵循與前面示例相同的邏輯?;赗edux操作的type屬性,我們?cè)诓恍薷默F(xiàn)有狀態(tài)的情況下計(jì)算新狀態(tài)。在switch語(yǔ)句的情況下,我們可以訪問特定于每個(gè)操作類型的text和index屬性,而不需要任何類型斷言。

never 類型

TypeScript 2.0引入了一個(gè)新原始類型never。never類型表示值的類型從不出現(xiàn)。具體而言,never是永不返回函數(shù)的返回類型,也是變量在類型保護(hù)中永不為true的類型。

這些是never類型的確切特征,如下所述:

  • never是所有類型的子類型并且可以賦值給所有類型。
  • 沒有類型是never的子類型或能賦值給never(never類型本身除外)。
  • 在函數(shù)表達(dá)式或箭頭函數(shù)沒有返回類型注解時(shí),如果函數(shù)沒有return語(yǔ)句,或者只有never類型表達(dá)式的return語(yǔ)句,并且如果函數(shù)是不可執(zhí)行到終點(diǎn)的(例如通過控制流分析決定的),則推斷函數(shù)的返回類型是never。
  • 在有明確never返回類型注解的函數(shù)中,所有return語(yǔ)句(如果有的話)必須有never類型的表達(dá)式并且函數(shù)的終點(diǎn)必須是不可執(zhí)行的。

聽得云里霧里的,接下來(lái),用幾個(gè)例子來(lái)講講never這位大哥。

永不返回的函數(shù)

下面是一個(gè)永不返回的函數(shù)示例:

// Type () => never
const sing = function() {
  while (true) {
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
    console.log("我就是不返回值,怎么滴!");
  }
}

該函數(shù)由一個(gè)不包含break或return語(yǔ)句的無(wú)限循環(huán)組成,所以無(wú)法跳出循環(huán)。因此,推斷函數(shù)的返回類型是never。

類似地,下面函數(shù)的返回類型被推斷為never

// Type (message: string) => never
const failwith = (message: string) => {
  throw new Error(message);
};

TypeScript 推斷出never類型,因?yàn)樵摵瘮?shù)既沒有返回類型注釋,也沒有可到達(dá)的端點(diǎn)(由控制流分析決定)。

不可能有該類型的變量

另一種情況是,never類型被推斷為從不為ture。在下面的示例中,我們檢查value參數(shù)是否同時(shí)是字符串和數(shù)字,這是不可能的。

function impossibleTypeGuard(value: any) {
  if (
    typeof value === "string" &&
    typeof value === "number"
  ) {
    value; // Type never
  }
}

這個(gè)例子顯然是過于作,來(lái)看一個(gè)更實(shí)際的用例。下面的示例展示了 TypeScript 的控制流分析縮小了類型守衛(wèi)下變量的聯(lián)合類型。直觀地說,類型檢查器知道,一旦咱們檢查了value是字符串,它就不能是數(shù)字,反之亦然

function controlFlowAnalysisWithNever(
  value: string | number
) {
  if (typeof value === "string") {
    value; // Type string
  } else if (typeof value === "number") {
    value; // Type number
  } else {
    value; // Type never
  }
}

注意,在最后一個(gè)else分支中,value既不能是字符串,也不能是數(shù)字。在這種情況下,TypeScript 推斷出never類型,因?yàn)樵蹅円呀?jīng)將value參數(shù)注解為類型為string | number,也就是說,除了string或number,value參數(shù)不可能有其他類型。

一旦控制流分析排除了string和number作為value類型的候選項(xiàng),類型檢查器就推斷出never類型,這是惟一剩下的可能性。但是,咱們也就不能對(duì)value做任何有用的事情,因?yàn)樗念愋褪莕ever,所以咱們的編輯器工具不會(huì)顯示自動(dòng)顯示提示該值有哪些方法或者屬性可用。

never 和 void 之間的區(qū)別

你可能會(huì)問,為什么 TypeScript 已經(jīng)有一個(gè)void類型為啥還需要never類型。雖然這兩者看起來(lái)很相似,但它們是兩個(gè)不同的概念:

沒有顯式返回值的函數(shù)將隱式返回undefined。雖然我們通常會(huì)說這樣的函數(shù)“不返回任何東西”,但它會(huì)返回。在這些情況下,我們通常忽略返回值。這樣的函數(shù)在 TypeScript 中被推斷為有一個(gè)void返回類型。

具有never返回類型的函數(shù)永不返回。它也不返回undefined。該函數(shù)沒有正常的完成,這意味著它會(huì)拋出一個(gè)錯(cuò)誤,或者根本不會(huì)完成運(yùn)行。

函數(shù)聲明的類型推斷

關(guān)于函數(shù)聲明的返回類型推斷有一個(gè)小問題。咱們前面列出的幾條never特征,你會(huì)發(fā)現(xiàn)下面這句話:

在函數(shù)表達(dá)式或箭頭函數(shù)沒有返回類型注解時(shí),如果函數(shù)沒有return語(yǔ)句,或者只有never類型表達(dá)式的return語(yǔ)句,并且如果函數(shù)是不可執(zhí)行到終點(diǎn)的(例如通過控制流分析決定的),則推斷函數(shù)的返回類型是never。

它提到了函數(shù)表達(dá)式和箭頭函數(shù),但沒有提到函數(shù)聲明。也就是說,為函數(shù)表達(dá)式推斷的返回類型可能與為函數(shù)聲明推斷的返回類型不同:

// Return type: void
function failwith1(message: string) {
  throw new Error(message);
}

// Return type: never
const failwith2 = function(message: string) {
  throw new Error(message);
};

這種行為的原因是向后兼容性,如下所述。如果希望函數(shù)聲明的返回類型never,則可以對(duì)其進(jìn)行顯式注釋:

function failwith1(message: string): never {
  throw new Error(message);
}

以上就是詳解TypeScript2.0標(biāo)記聯(lián)合類型的詳細(xì)內(nèi)容,更多關(guān)于TS2.0標(biāo)記聯(lián)合類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論