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

詳解TypeScript中的箭頭函數如何實現重載

 更新時間:2023年05月26日 08:30:01   作者:芋仔  
這篇文章主要為大家詳細介紹了TypeScript中的箭頭函數是如何實現重載的,文中的示例代碼講解詳細,具有一定的參考價值,需要的可以參考一下

這個問題來自于我在網上搜索的時候,基本上清一色的翻譯官網的函數重載的章節(jié)的內容,對于我想要的箭頭函數的重載沒有太多幫助。包括官網,其實也沒有非常明確的說明箭頭函數該如何重載。

這里先直接上結論,在 ts 中,可以借助 Call Signatures 這個特性來實現箭頭函數的重載。原本是用來給函數聲明增加靜態(tài)屬性的,但是卻可以用來完成箭頭函數的類型聲明。

type Test = {
  (s: string): string;
  (s: number): number;
  (s: string, b: number): number;
};
type getState<T> = {
  (): T;
  <K extends keyof T>(key: K): T[K];
};

本質就是定一個新的類型,鍵值就用括號包,里面就是不同的入參,函數的返回值就是鍵值即可。

但是不出意外的話,意外就會發(fā)生,在實操的時候,往往這么寫非常不 ok。

實操

實戰(zhàn)中這么寫,類型聲明是好寫的,但是函數的實現,其實并不好寫,以這樣一個函數為例:

const deal = (a: number | string, b: number | string): number | string => {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
  if (typeof a === 'string' || typeof b === 'string') {
    return String(a) + String(b);
  }
  return 0;
};

當入參都是 number 時,返回 number,入參有一個是 string 時,返回 string。

那么對于這樣一個函數,其實存在幾個重載的情況:

type Deal1 = {
  (a: number, b: number): number;
  (a: number, b: string): string;
  (a: string, b: number): string;
  (a: string, b: string): string;
};

要想把上述類型賦值給 deal 函數,會出現返回值匹配不上的問題。

// ts 會提示類型錯誤:
// Type '(a: number | string, b: number | string) => number | string' is not assignable to type 'Deal1'.
// Type 'string | number' is not assignable to type 'number'.
const deal: Deal1 = (
  a: number | string,
  b: number | string,
): number | string => {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
  if (typeof a === 'string' || typeof b === 'string') {
    return String(a) + String(b);
  }
???????  return 0;
};

從現象來看,ts 對于這樣的寫法在做檢查的時候,會將當前函數對重載的幾個類型都進行檢查,看看類型上是否能夠賦值,相當于:

// 偽代碼,理解意思就行
check1: (a: number, b: number) => number = (a: number | string, b: number | string) => number | string);
check2: (a: number, b: string) => string = (a: number | string, b: number | string) => number | string);
check3: (a: string, b: number) => string = (a: number | string, b: number | string) => number | string);
check4: (a: string, b: string) => string = (a: number | string, b: number | string) => number | string);

對于入參,由于是逆變位置,所以 number = number | string 能夠賦值,所以參數的類型能夠通過校驗,而返回值屬于順變位置,所以 number = number | string 是不能通過類型校驗的。

想要將返回值賦值成功,返回值必須是 number & string 或者 any,前者就是 never 了,此時會發(fā)現雖然賦值通過了 deal 的校驗,但是函數的實現中,就會報返回值錯誤的問題。如果改成 any,那么雖然不會報錯,但是在函數中就缺失了對返回值的檢查。如下:

// 返回值改為 number & string,
// 賦值處能夠避免類型錯誤
const deal: Deal1 = (
  a: number | string,
  b: number | string,
): number & string => {
  if (typeof a === 'number' && typeof b === 'number') {
    // 此時返回值是 never,此處會報類型錯誤
    return a + b;
  }
  if (typeof a === 'string' || typeof b === 'string') {
    // 此時返回值是 never,此處會報類型錯誤
    return String(a) + String(b);
  }
  // 此時返回值是 never,此處會報類型錯誤
  return 0;
};
// 返回值改為 any,
// 賦值處能夠避免類型錯誤
const deal: Deal1 = (a: number | string, b: number | string): any => {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
  if (typeof a === 'string' || typeof b === 'string') {
    return String(a) + String(b);
  }
  // 此處寫任何類型都不會拋錯,缺失了原本的期望的校驗
  return undefined;
};

那么目前看,想要用這種方式實現箭頭函數的重載,就只能將返回值設定為 any,這樣,雖然在用戶使用的時候能夠進行非常好的類型提示,但是開發(fā)者本身不能再借助 ts 完成對這個函數的返回值的校驗。

此時還有一種寫法,就是 as,寫法如下:

const deal = ((a: string | number, b: number | string): number | string => {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
  if (typeof a === 'string' || typeof b === 'string') {
    return String(a) + String(b);
  }
  return 0;
}) as Deal1;

這樣的寫法,即能夠滿足函數本身的返回值校驗 (可以把 0 改成其他類型試試),同時,又具備了 Deal1 的重載的類型聲明:

// case1: number
const case1 = deal(1, 2);
// case2: string
const case2 = deal('1', 2);
// case3: never,入參類型錯誤
const case3 = deal({}, 2);

最佳實踐

附上完整的代碼:

// 重載類型聲明
type Deal1 = {
  (a: number, b: number): number;
  (a: number, b: string): string;
  (a: string, b: number): string;
  (a: string, b: string): string;
};
const deal = ((
  // 此時入參,返回值的類型可自行限制
  // 無需掛念 Deal1 中的定義
  a: string | number,
  b: number | string,
): number | string => {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
  if (typeof a === 'string' || typeof b === 'string') {
    return String(a) + String(b);
  }
  // 這樣寫,原函數具備校驗的能力
  return 0;
  // 通過 as 指定類型
}) as Deal1;
const case1 = deal(1, 2);
const case2 = deal('1', 2);
const case3 = deal({}, 2);

核心就是原函數類型寫法一致,重載的類型通過 as 進行賦值,這樣就兼顧了類型提示和原函數的類型校驗。

其他方法

由于 type 和 interface 的用法在此處并無歧義,所以換成 interface 也是 ok。

另一種就是函數的交叉,也是實現重載的一種方案,如下:

type Deal3 = ((a: number, b: number) => number) &
  ((a: number, b: string) => string) &
  ((a: string, b: number) => string) &
  ((a: string, b: string) => string);

總結

本文介紹了 TS 實現箭頭函數重載的幾種方案,借助了 Call Signatures 的特性。

同時給出了這樣寫,在實戰(zhàn)中可能會遇到的類型不匹配的問題及解決方案。希望能夠對遇到同樣問題的同學有所幫助吧。

到此這篇關于詳解TypeScript中的箭頭函數如何實現重載的文章就介紹到這了,更多相關TypeScript函數重載內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關文章

  • window.onload 加載完畢的問題及解決方案(上)

    window.onload 加載完畢的問題及解決方案(上)

    我們經常使用 window.onload 來處理頁面,當頁面加載完成做一些事情。但這個 window.onload 是頁面全部加載完成,甚至包括圖片,而我們實際上經常需要的是文檔 DOM 加載完畢!
    2009-07-07
  • JavaScript實現淺拷貝與深拷貝的方法分析

    JavaScript實現淺拷貝與深拷貝的方法分析

    這篇文章主要介紹了JavaScript實現淺拷貝與深拷貝的方法,結合實例形式總結分析了JavaScript淺拷貝與深拷貝的定義與使用方法,需要的朋友可以參考下
    2018-07-07
  • JS實現拖動模態(tài)框案例

    JS實現拖動模態(tài)框案例

    這篇文章主要為大家詳細介紹了JS實現拖動模態(tài)框案例,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • ES6中l(wèi)et、const的區(qū)別及變量的解構賦值操作方法實例分析

    ES6中l(wèi)et、const的區(qū)別及變量的解構賦值操作方法實例分析

    這篇文章主要介紹了ES6中l(wèi)et、const的區(qū)別及變量的解構賦值操作方法,結合實例形式分析了ES6中l(wèi)et、const的功能、原理、使用方法及數組、字符串、函數參數等解構賦值相關操作技巧,需要的朋友可以參考下
    2019-10-10
  • 用JavaScript實現簡單網頁時鐘

    用JavaScript實現簡單網頁時鐘

    這篇文章主要為大家詳細介紹了用JavaScript實現簡單網頁時鐘,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • js實時獲取窗口大小變化的實例代碼

    js實時獲取窗口大小變化的實例代碼

    下面小編就為大家?guī)硪黄猨s實時獲取窗口大小變化的實例代碼。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • JavaScript?排他思想的具體實現

    JavaScript?排他思想的具體實現

    排他思想的算法就是排除掉其他的,本文主要介紹了JavaScript?排他思想的實現,以及介紹了兩個示例,感興趣的可以了解一下
    2021-11-11
  • 輪播圖組件js代碼

    輪播圖組件js代碼

    這篇文章主要為大家介紹了輪播圖組件JavaScript代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 微信小程序仿微信運動步數排行(交互)

    微信小程序仿微信運動步數排行(交互)

    這篇文章主要介紹了微信小程序仿微信運動步數排行(交互),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • 使用Cookies保存網站歷史瀏覽記錄實例代碼

    使用Cookies保存網站歷史瀏覽記錄實例代碼

    仿淘寶網的最近瀏覽記錄功能,喜歡的朋友可以參考下。
    2010-07-07

最新評論