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

TypeScript路由参数类型校验问题:禁止不符参数传入函数

问题:TypeScript路由参数类型校验失效

我把所有API路由归到一个enum里,用来根据URL参数生成对应对象。但在将对象传入接受不同参数结构的函数时,TypeScript错误地允许了本不应被接受的对象——比如传入缺少目标路由必填属性的params对象,编译器却没报错。

enum Routes {
  WorkflowRun = "/workflows/:workflowId/runs/:runId",
  WorkflowRunTest = "/workflows/:foo/runs/:bar",
}

type Split<S extends string, SEP extends string, Result extends string[] = []> = 
  S extends `${infer _}`
  ? S extends `${infer L}${SEP}${infer R}`
    ? Split<R, SEP, [...Result, L]>
    : S extends ''
      ? SEP extends '' ? [...Result] : [S]
      : [...Result, S]
  : string[]

type Parts = Split<Routes.WorkflowRun, '/'>
    // ^? ["", "workflow", ":workflowId", "runs", ":runId"] 

type ParamValue = number | string

type GetRouteParams<Route extends string> = {
    [K in Split<Route, '/'>[number] as K extends `:${infer Param}` ? Param : never]: ParamValue
}

type Test = GetRouteParams<Routes.WorkflowRun>
// { workflowId: string | number; runId: string | number } 👍

function replaceParams<R extends Routes, P extends GetRouteParams<R>>(route: R, params: P): string {
  let finalRoute = route

  for (const key in params) {
    const value = params[key] as ParamValue
    finalRoute.replace(key, value.toString())
  }

  return finalRoute
}

function getWorkflowRun(params: GetRouteParams<Routes.WorkflowRun>) {
  const route = replaceParams(Routes.WorkflowRunTest, params)
  // 为何缺少foo和bar属性的params仍被允许?
}

修复方案

问题根源在于replaceParams的泛型约束过于宽松:P extends GetRouteParams<R>允许传入目标参数类型的子类型,而TypeScript的结构类型系统会误判无重叠属性的对象为符合约束。

步骤1:收紧泛型约束

直接要求params严格匹配目标路由对应的参数类型,去掉多余的泛型参数P:

function replaceParams<R extends Routes>(route: R, params: GetRouteParams<R>): string {
  let finalRoute = route

  for (const key in params) {
    const paramKey = `:${key}`; // 路由参数带冒号,需匹配完整格式
    finalRoute = finalRoute.replace(paramKey, params[key].toString())
  }

  return finalRoute
}

步骤2:修正字符串替换逻辑

原代码中finalRoute.replace(...)不会修改原字符串(replace返回新字符串),且未匹配路由参数的冒号前缀,修正后才能正确替换参数。

效果验证

修改后,传入不符合目标路由参数结构的对象会直接触发TypeScript错误:

function getWorkflowRun(params: GetRouteParams<Routes.WorkflowRun>) {
  const route = replaceParams(Routes.WorkflowRunTest, params)
  // 报错:类型“GetRouteParams<Routes.WorkflowRun>”的参数不能赋给类型“GetRouteParams<Routes.WorkflowRunTest>”的参数。
  // 属性“foo”在类型“GetRouteParams<Routes.WorkflowRun>”中缺失,但在类型“GetRouteParams<Routes.WorkflowRunTest>”中是必需的。
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:14:56