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

优化TypeScript模板字面量与映射类型的API类型推断实现

优化TypeScript API类的路由类型推断逻辑

我想用TypeScript类型系统构建一个API类,能根据传入的后端路由字符串自动推断返回数据类型。但部分路由包含数字参数,当前实现需要写大量条件类型分支,新增路由时会越来越繁琐。

现有实现代码:

// 假设已定义这些接口
interface IAkey {}
interface IUserDevice {}
interface IMessageForwarding {}

type ResourceType = 'api_keys' | 'message_forwardings' | `devices/${number}/user_devices`
type ResourceMap = {
  api_keys: IAkey[],
  user_devices: IUserDevice[],
  message_forwardings: IMessageForwarding[]
}

type DataType<T extends ResourceType> =
    T extends keyof ResourceMap
        ? ResourceMap[T]
        : T extends `devices/${number}/user_devices`
            ? ResourceMap['user_devices']
            : never

class RestApiService<T extends ResourceType> {
    resource: T
    data: DataType<T>

    constructor(resource: T){
        this.resource = resource
    }

    // 请求方法示例
    async get(): Promise<DataType<T>> {
        // 实际请求逻辑
        return {} as DataType<T>
    }
}

当前实现可以正常工作:

const apiKeysData = new RestApiService('api_keys').data // 推断为 IAkey[]
new RestApiService('some_route') // 类型错误:'some_route' 不属于 ResourceType
const userDeviceData = new RestApiService('devices/1234/user_devices').data // 推断为 IUserDevice[]

但新增更多带模板字面量的路由(比如users/${number}/profile、orders/${number}/items)时,DataType的条件类型分支会越来越多,维护成本很高。有没有办法优化这个泛型类型,不用每次加路由都新增条件分支?


优化方案

可以通过统一的路由模板到资源类型的映射,结合TypeScript的模板字面量类型匹配能力解决这个问题,彻底避免手写大量条件分支。

具体实现步骤

  1. 定义路由模板与数据类型的直接映射
    创建一个包含所有路由(包括带参数的模板)的映射表,直接关联路由到对应的数据类型:

    // 假设已定义这些接口
    interface IAkey {}
    interface IUserDevice {}
    interface IMessageForwarding {}
    interface IUserProfile {}
    interface IOrderItem {}
    
    // 路由模板 -> 对应数据类型的映射
    type RouteTypeMap = {
      'api_keys': IAkey[],
      'message_forwardings': IMessageForwarding[],
      `devices/${number}/user_devices`: IUserDevice[],
      `users/${number}/profile`: IUserProfile[],
      `orders/${number}/items`: IOrderItem[]
    }
    
  2. 自动推导合法路由类型
    无需手动维护ResourceType,直接从映射表的键中提取所有合法路由:

    type ResourceType = keyof RouteTypeMap
    
  3. 简化数据类型推断逻辑
    直接通过路由类型从映射表中取值,完全省去条件分支:

    type DataType<T extends ResourceType> = RouteTypeMap[T]
    
  4. 重构API类
    现在API类可以直接复用上述类型,逻辑更简洁:

    class RestApiService<T extends ResourceType> {
        resource: T
        data: DataType<T>
    
        constructor(resource: T){
            this.resource = resource
        }
    
        async get(): Promise<DataType<T>> {
            return {} as DataType<T>
        }
    }
    

验证效果

// 正确推断数据类型
const apiKeysData = new RestApiService('api_keys').data // IAkey[]
const userDeviceData = new RestApiService('devices/1234/user_devices').data // IUserDevice[]
const profileData = new RestApiService('users/567/profile').data // IUserProfile[]

// 非法路由自动报错
new RestApiService('invalid_route') // 类型错误:'invalid_route' 不能赋值给 ResourceType

扩展优势

  • 新增路由时,只需在RouteTypeMap中添加对应模板和类型,无需修改其他逻辑
  • 路由模板的参数类型(如${number})可直接限制传入路由的格式合法性
  • 类型推断完全由TypeScript自动处理,避免手动维护条件分支的遗漏或错误

内容的提问来源于stack exchange,提问作者s.Bergmann

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:53:14