You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript实现枚举映射路由与DTO的泛型API方法

问题描述

现有20余个结构完全一致的接口请求方法,仅路由路径与返回DTO类型存在差异。为避免调用时重复传入路由、类型参数造成逻辑冗余,需要改造为仅传入实体标识(如Asset、Personnel)即可完成调用的通用方法。
原有重复实现示例:

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

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

期望改造后支持传入枚举类参数,比如传入Entity.Asset或Entity.Personnel,方法内部自动匹配对应路由与返回DTO类型。
目前已做的尝试:

  1. 定义实体类型:
export type Asset = {
    route: '/assets/asset',
    dto: AssetDto[]
}

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

export type Entity = Asset | Personnel
  1. 编写泛型方法初稿:
async getAll<T extends Entity>(entity: T) {
    return await this.get<typeof entity.Dto>(entity.route)
}

当前卡点:不清楚如何通过传入类型/枚举值完成调用,不确定该思路是否可行,期望的调用形式如下:

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

实现方案

你的核心思路是对的,问题出在混淆了TypeScript的类型空间和JavaScript的运行时值空间:你之前定义的Asset/Personnel/Entity都只是TS类型,编译为JS后会被完全擦除,根本不能作为运行时参数传入函数。要实现需求,需要先定义运行时真实存在的枚举/常量作为传参标识,再通过TS类型映射关联标识对应的路由和返回类型。

  • 第一步:定义运行时可用的实体枚举和类型映射
// 传参用的枚举,是真实存在的JS值,编译后不会消失
export enum EntityType {
  Asset = 'Asset',
  Personnel = 'Personnel'
}

// 类型映射表,用来关联每个枚举值对应的返回类型、路由字面量类型
export interface EntityMap {
  [EntityType.Asset]: {
    route: 'assets/assets',
    returnType: AssetDto[]
  },
  [EntityType.Personnel]: {
    route: 'personnel/personnels',
    returnType: PersonnelDto[]
  }
  // 后续新增同类接口,只需要在这里加对应配置即可,不需要修改通用方法
}
  • 第二步:抽离路由常量配置
    路由是运行时需要用到的值,必须单独定义为JS常量,不能靠TS类型获取:
const ROUTE_MAP: Record<EntityType, string> = {
  [EntityType.Asset]: 'assets/assets',
  [EntityType.Personnel]: 'personnel/personnels'
} as const
  • 第三步:实现通用泛型方法
    通过泛型约束自动推导传入实体对应的返回类型,不需要调用方手动传入泛型参数:
async getAll<T extends EntityType>(entity: T) {
  return await this.get<EntityMap[T]['returnType']>(ROUTE_MAP[entity])
}

调用效果

完全匹配你期望的调用形式,TS会自动推导返回值类型,不需要额外标注:

async testCall() {
  // assetList 自动推导为 AssetDto[] 类型
  const assetList = await this.getAll(EntityType.Asset)
  // personnelList 自动推导为 PersonnelDto[] 类型
  const personnelList = await this.getAll(EntityType.Personnel)
}

注意:所有需要在运行时读取的配置(比如路由路径)都必须写成JS可执行的常量/枚举,不要尝试直接读取TS类型的属性,TS类型不会出现在最终运行的JS代码里。


内容的提问来源于stack exchange,提问作者JamesG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:18:19