[英]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.