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

Typescript如何定义特定值组合联合类型解决API handler访问报错

TypeScript 实现按资源操作权限约束API映射访问类型

问题背景

现有按资源分类的API处理函数集合,结构如下:

const API = {
  A: {
    CREATE: createA,
    UPDATE: updateA,
    DELETE: deleteA
  },
  B: {
    CREATE: createB,
    UPDATE: updateB
    // B资源无DELETE处理函数
  },
  C: {
    CREATE: createC,
    UPDATE: updateC,
    DELETE: deleteC
  }
}

需要实现getHandler方法,根据传入的资源名和操作名返回对应的处理函数。初始实现将key和action都定义为全量联合类型时,TS会提示B资源不存在DELETE属性的类型错误;手动拆分KeyAction为判别联合类型后,报错依然存在。

原因说明

手动拆分联合类型不生效的核心原因是:函数参数直接解构后,TS会把key和action判定为两个独立的联合类型变量,丢失了两者的绑定约束关系——即不会记住「当key为B时,action只能是CREATE/UPDATE」的规则,因此会认为action可能取到DELETE,导致访问API[key][action]时报错。

可落地方案

方案1:基于实际API结构反向推导类型(推荐,零额外类型维护成本)

通过as const锁定API对象的字面量类型,再反向映射生成所有合法的入参组合,配合泛型保留key和action的绑定关系:

// 示例处理函数定义
const createA = () => {}
const updateA = () => {}
const deleteA = () => {}
const createB = () => {}
const updateB = () => {}
const createC = () => {}
const updateC = () => {}
const deleteC = () => {}

// 给API对象加as const,锁定精确的属性结构
const API = {
  A: {
    CREATE: createA,
    UPDATE: updateA,
    DELETE: deleteA
  },
  B: {
    CREATE: createB,
    UPDATE: updateB
  },
  C: {
    CREATE: createC,
    UPDATE: updateC,
    DELETE: deleteC
  }
} as const

// 从API实际结构反向生成所有合法的(key, action)组合类型
type KeyAction = {
  [K in keyof typeof API]: {
    key: K
    action: keyof typeof API[K]
  }
}[keyof typeof API]

// 用泛型+Extract绑定入参中key和action的对应关系
const getHandler = <K extends KeyAction['key']>(params: Extract<KeyAction, { key: K }>) => {
  const { key, action } = params
  return API[key][action]
}

该实现的效果:

  • 传入非法组合比如{key: 'B', action: 'DELETE'}时,TS会直接抛出类型错误,符合业务约束
  • 访问API[key][action]无任何类型报错
  • 后续新增、修改API的资源或操作时,不需要手动更新类型定义,TS会自动同步推导合法入参范围

方案2:手动定义API类型约束(适合需要明确标注API类型的场景)

如果需要显式约束API对象的结构,可以先手动定义API的接口类型,再基于接口推导合法入参:

// 先定义API的类型约束
interface APIType {
  A: {
    CREATE: () => void
    UPDATE: () => void
    DELETE: () => void
  }
  B: {
    CREATE: () => void
    UPDATE: () => void
  }
  C: {
    CREATE: () => void
    UPDATE: () => void
    DELETE: () => void
  }
}

// 声明API时绑定类型
const API: APIType = {
  A: { CREATE: createA, UPDATE: updateA, DELETE: deleteA },
  B: { CREATE: createB, UPDATE: updateB },
  C: { CREATE: createC, UPDATE: updateC, DELETE: deleteC }
}

// 基于接口反向推导KeyAction
type KeyAction = {
  [K in keyof APIType]: {
    key: K
    action: keyof APIType[K]
  }
}[keyof APIType]

const getHandler = <K extends keyof APIType>(params: Extract<KeyAction, { key: K }>) => {
  const { key, action } = params
  return API[key][action]
}

注意:不要在函数入参位置直接解构,会导致TS丢失类型绑定关系,在函数体内解构即可避免该问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 04:15:30