簡體   English   中英

以類型為參數的通用 TypeScript API

[英]Generic TypeScript API with types as parameters

假設我有兩個這樣的函數(我目前有 20 個看起來幾乎相同的不同函數。唯一的區別是路由和 DTO)我不想在函數調用中同時發送路由和 DTO,因為那樣會使該函數調用更混亂/復雜。 所以我寧願只用 Asset | 調用它。 人事 | 其他有效的東西

 async getAllAssets() {
    return await this.get<AssetDto[]>('assets/assets')
  }

 async getAllPersonnels() {
    return await this.get<PersonnelDto[]>('personnel/personnels')
  }

我想讓它更通用,所以我只需要一個函數而不是兩個。 我該如何實施? 我自己的嘗試如下。 也許它會讓我更清楚我真正想要什么。 我是 TypeScript 的新手,只用了一周。 我的“夢想”實現還將包括枚舉,因此我可以使用例如 Entity.Asset 或 Entity.Personnel 調用該函數,然后在引擎蓋下它知道它應該為 Asset 或 Personnel 使用路由和 dto。

export type Asset = {
    route: '/assets/asset',
    dto: AssetDto[]
}

export type Personnel = {
    route: '/personnel/personnel',
    dto: PersonnelDto[]
}

export type Entity = Asset | Personnel

這是一個更通用的函數的例子:

 async getAll<T extends Entity>(entity: T) {
    return await this.get<typeof entity.Dto>(entity.route)
  }

但我不知道如何用類型實際調用函數? 或者甚至可以這樣做嗎?

  async howIWantAFunctionCallToBeLike() {
    await this.getAll(Entity.Asset))
  }

正如 Tobias 所說,你需要一些東西來生存到運行時才能傳遞給你的泛型函數。 我建議使用一個簡單的泛型類:

class Route<T> {
  constructor(readonly path: string) {
  }

  transform(data: unknown): T[] {
    // unsafe cast by default; subclasses could do something more
    return data as T[];
  }
}

const personnelRoute = new Route<PersonnelDto>('/personnel/personnel');

async function getAll<T>(route: Route<T>): Promise<T[]> {
  return route.transform(await doFetch(route.path));
}

可以在這里使用泛型來根據傳遞給函數的內容來推斷返回類型。

您可以創建這樣的界面:

interface Entities {
  '/assets/asset': AssetDto[],
  '/personnel/personnel': PersonnelDto[]
} 

使用這個接口,我們可以創建一個泛型函數,它根據傳遞的路由返回正確的類型。

async getGeneric<T extends keyof Entities>(route: T){
  return await this.get<Entities[T]>(route)
} 

async otherFn() {
  const a = await this.getGeneric('/assets/asset')
  //    ^? AssetDto[]
  const b = await this.getGeneric('/personnel/personnel')
  //    ^? PersonnelDto[]
}

操場


或使用枚舉:

enum Routes {
  Asset = '/assets/asset',
  Personnel= '/personnel/personnel'
}

interface Entities {
  [Routes.Asset]: AssetDto[],
  [Routes.Personnel]: PersonnelDto[]
} 
async getGeneric<T extends keyof Entities>(route: T){
  return await this.get<Entities[T]>(route)
} 

async howIWantAFunctionCallToBeLike() {
  const a = await this.getGeneric(Routes.Asset)
  //    ^? AssetDto[]
  const b = await this.getGeneric(Routes.Personnel)
  //    ^? PersonnelDto[]
  }

操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM