溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

TypeScript泛型推斷怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2022-08-17 16:12:40 來(lái)源:億速云 閱讀:169 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“TypeScript泛型推斷怎么實(shí)現(xiàn)”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“TypeScript泛型推斷怎么實(shí)現(xiàn)”文章能幫助大家解決問(wèn)題。

基礎(chǔ)類型準(zhǔn)備

  • 用一個(gè)枚舉來(lái)定義Animal的類型

enum EAnimalType {
  dog = 'dog',
  cat = 'cat',
  bird = 'bird',
}
  • 定義不同類型的動(dòng)物有不同的能力類型

type Dog = {
  /** 大叫 */
  shoutLoudly: () => void;
}
type Cat = {
  say: () => void;
}
type Bird = {
  /** 飛 */
  fly: () => void;
}
  • 定義一個(gè)動(dòng)物的映射類型

 type AnimalMap = {
  [EAnimalType.dog]: Dog;
  [EAnimalType.cat]: Cat;
  [EAnimalType.bird]: Bird;
}

最終使用的方式

/**
 * 定義一個(gè)工廠,用來(lái)創(chuàng)建具體動(dòng)物的實(shí)例
 * @returns 返回動(dòng)物的實(shí)例
 */
function createAnimalFactory<T extends EAnimalType>(): IAnimal<T> {
  // TODO 根據(jù)業(yè)務(wù)具體實(shí)現(xiàn)
  return {} as IAnimal<T>;
}
// 根據(jù)泛型創(chuàng)建狗狗的實(shí)例
const dog = createAnimalFactory<EAnimalType.dog>();
dog.shoutLoudly();
// 根據(jù)泛型創(chuàng)建鳥(niǎo)的實(shí)例
const bird = createAnimalFactory<EAnimalType.bird>();
bird.fly()

基于Interface的實(shí)現(xiàn) (失敗了)

  • 接著我們創(chuàng)建一個(gè)interface 來(lái)定義動(dòng)物基礎(chǔ)接口

export interface IAnimal<T extends EAnimalType> extends IAnimalExtra<T> {
  id: number;   // 編號(hào)
  name: string;   // 名稱
  type: T;   // 類型
}

我們看到IAnimal接口繼承了IAnimalExtra接口,我們想的是通過(guò)泛型T來(lái)動(dòng)態(tài)推導(dǎo)出真實(shí)的類型。讓我們來(lái)看看IAnimalExtra接口怎么寫(xiě)

  • 寫(xiě)IAnimalExtra接口

export type IAnimalExtra<T extends EAnimalType>  {
  [c in keyof AnimalMap[T]]: AnimalMap[T][c];
}

TypeScript泛型推斷怎么實(shí)現(xiàn)

我們這樣寫(xiě),發(fā)現(xiàn)調(diào)試控制臺(tái)報(bào)了很多錯(cuò),具體分析了下錯(cuò)誤,接口不支持這種功能。接著我們嘗試,改成type試一下。

  • 最后用type 去替代 IAnimalExtra

export type IAnimalExtra<T extends EAnimalType> = {
  [c in keyof AnimalMap[T]]: AnimalMap[T][c];
}

我們用type,果然不不錯(cuò)了,證明我們的思路是對(duì)的。乍一看,寫(xiě)的怎么復(fù)雜[c in keyof AnimalMap[T]]: AnimalMap[T][c]; 不要怕,我們先具體分析一下這段代碼,就很好理解了。

  • 先看AnimalMap[T],可以理解從AnimalMap類型中獲取對(duì)應(yīng)的類型,近似js中從對(duì)象取值

  • keyof 接受一個(gè)Object,生成Object的key的字符串的union(聯(lián)合)

  • in 可以遍歷枚舉類型,類似 for...in

整體的功能就是根據(jù)泛型T,獲取AnimalMap中的某個(gè)類型,遍歷。

  • extends IAnimalExtra<T> 報(bào)錯(cuò)了

TypeScript泛型推斷怎么實(shí)現(xiàn)

在我們最終認(rèn)為可以的情況下,發(fā)現(xiàn)有報(bào)錯(cuò)了,內(nèi)容為【接口只能擴(kuò)展對(duì)象類型或?qū)ο箢愋团c靜態(tài)已知成員的交集】

所有內(nèi)容都基于type 實(shí)現(xiàn)

在我們嘗試了多次之后,發(fā)現(xiàn)Interface怎么也滿足不了需求,接著我們都換成type去試試。

export type IAnimal<T extends EAnimalType> = IAnimalExtra<T> & {
  id: number;   // 編號(hào)
  name: string;   // 名稱
  type: T;   // 類型
}

這里我們用了&交叉類型類合并接口的類型。

換成type之后,已能完全滿足我們的需求,能根據(jù)泛型推斷出我們想要的類型。

完整Demo

/**
 * 動(dòng)物枚舉
 */
export enum EAnimalType {
  dog = 'dog',
  cat = 'cat',
  bird = 'bird',
}
type Dog = {
  /** 大叫 */
  shoutLoudly: () => void;
}
type Cat = {
  say: () => void;
}
type Bird = {
  /** 飛 */
  fly: () => void;
}
export type AnimalMap = {
  [EAnimalType.dog]: Dog;
  [EAnimalType.cat]: Cat;
  [EAnimalType.bird]: Bird;
}
export type IAnimalExtra<T extends EAnimalType> = {
  [c in keyof AnimalMap[T]]: AnimalMap[T][c];
}
export type IAnimal<T extends EAnimalType> = IAnimalExtra<T> & {
  id: number;   // 編號(hào)
  name: string;   // 名稱
  type: T;   // 類型
}
/**
 * 定義一個(gè)工廠,用來(lái)創(chuàng)建具體動(dòng)物的實(shí)例
 * @returns 返回動(dòng)物的實(shí)例
 */
function createAnimalFactory<T extends EAnimalType>(): IAnimal<T> {
  // TODO 根據(jù)業(yè)務(wù)具體實(shí)現(xiàn)
  return {} as IAnimal<T>;
}
// 根據(jù)泛型創(chuàng)建狗狗的實(shí)例
const dog = createAnimalFactory<EAnimalType.dog>();
dog.shoutLoudly();
// 根據(jù)泛型創(chuàng)建鳥(niǎo)的實(shí)例
const bird = createAnimalFactory<EAnimalType.bird>();
bird.fly();

關(guān)于“TypeScript泛型推斷怎么實(shí)現(xiàn)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI