亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解TypeScript中的箭頭函數(shù)如何實(shí)現(xiàn)重載

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

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

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

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

本質(zhì)就是定一個(gè)新的類型,鍵值就用括號(hào)包,里面就是不同的入?yún)?,函?shù)的返回值就是鍵值即可。

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

實(shí)操

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

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

當(dāng)入?yún)⒍际?number 時(shí),返回 number,入?yún)⒂幸粋€(gè)是 string 時(shí),返回 string。

那么對(duì)于這樣一個(gè)函數(shù),其實(shí)存在幾個(gè)重載的情況:

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

要想把上述類型賦值給 deal 函數(shù),會(huì)出現(xiàn)返回值匹配不上的問題。

// ts 會(huì)提示類型錯(cuò)誤:
// 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;
};

從現(xiàn)象來看,ts 對(duì)于這樣的寫法在做檢查的時(shí)候,會(huì)將當(dāng)前函數(shù)對(duì)重載的幾個(gè)類型都進(jìn)行檢查,看看類型上是否能夠賦值,相當(dāng)于:

// 偽代碼,理解意思就行
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);

對(duì)于入?yún)?,由于是逆變位置,所?number = number | string 能夠賦值,所以參數(shù)的類型能夠通過校驗(yàn),而返回值屬于順變位置,所以 number = number | string 是不能通過類型校驗(yàn)的。

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

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

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

此時(shí)還有一種寫法,就是 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;

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

// case1: number
const case1 = deal(1, 2);
// case2: string
const case2 = deal('1', 2);
// case3: never,入?yún)㈩愋湾e(cuò)誤
const case3 = deal({}, 2);

最佳實(shí)踐

附上完整的代碼:

// 重載類型聲明
type Deal1 = {
  (a: number, b: number): number;
  (a: number, b: string): string;
  (a: string, b: number): string;
  (a: string, b: string): string;
};
const deal = ((
  // 此時(shí)入?yún)?,返回值的類型可自行限?
  // 無需掛念 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);
  }
  // 這樣寫,原函數(shù)具備校驗(yàn)的能力
  return 0;
  // 通過 as 指定類型
}) as Deal1;
const case1 = deal(1, 2);
const case2 = deal('1', 2);
const case3 = deal({}, 2);

核心就是原函數(shù)類型寫法一致,重載的類型通過 as 進(jìn)行賦值,這樣就兼顧了類型提示和原函數(shù)的類型校驗(yàn)。

其他方法

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

另一種就是函數(shù)的交叉,也是實(shí)現(xiàn)重載的一種方案,如下:

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

總結(jié)

本文介紹了 TS 實(shí)現(xiàn)箭頭函數(shù)重載的幾種方案,借助了 Call Signatures 的特性。

同時(shí)給出了這樣寫,在實(shí)戰(zhàn)中可能會(huì)遇到的類型不匹配的問題及解決方案。希望能夠?qū)τ龅酵瑯訂栴}的同學(xué)有所幫助吧。

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

相關(guān)文章

最新評(píng)論