繁体   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