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

如何让TypeScript动态推断动态生成路由函数的参数类型?

如何让TypeScript动态推断路由函数的参数类型?

我需要将路由对象动态转换为同时支持静态和动态调用的函数,例如针对路由/posts/:id,可以这样使用:

// 静态声明,输出为 /posts/:id
<Route path={ROUTES.singlePost()} />

// 动态调用,id=1时输出为 /posts/1
navigate(ROUTES.singlePost(someId))

当前的实现代码如下:

const rawRoutes = [{ key: "singlePost", path: "/posts/:id" }]

export const ROUTES = rawRoutes.reduce(
  (acc, item) => ({
    ...acc,
    [item.key]: buildRouteFn(item.path),
  }),
  {} as Record<IRouteKey, (...args: string[]) => string>,
)

function buildRouteFn(path: string) {
  return (...args: string[]) =>
    args.reduce((_path, arg) => _path.replace(/:\w+/, arg), path)
}

type IRouteKey = typeof rawRoutes[number]["key"]

目前的问题是,TypeScript的自动补全无法显示实际的参数信息(比如id?: string)。请问有没有办法让TypeScript动态推断这些参数类型?

我可以退而求其次使用如下方案,但这种拆分静态和动态函数的方式可读性和维护性较差:

export const ROUTES = {
  singlePostStatic: () => "/posts/:id",
  singlePostDynamic: (id: string) => `/posts/${id}`,
}

解决方案:利用TypeScript模板字符串类型实现动态参数推断

通过自定义类型解析路径中的参数,并结合映射类型为每个路由生成精确的函数类型,可以实现自动补全和类型检查。

1. 定义参数提取与函数类型

// 提取路径中的参数名,返回参数名组成的元组类型
type ExtractRouteParams<T extends string> = 
  T extends `${string}:${infer Param}/${infer Rest}` 
    ? [Param, ...ExtractRouteParams<Rest>]
    : T extends `${string}:${infer Param}`
      ? [Param]
      : [];

// 根据参数元组生成对应的函数类型
type RouteFunction<T extends string> = 
  ExtractRouteParams<T> extends []
    ? () => T
    : (...args: { [K in keyof ExtractRouteParams<T>]: string }) => string;

2. 重构路由定义与生成逻辑

// 使用const断言让TypeScript保留路径的字面量类型
const rawRoutes = [{ key: "singlePost", path: "/posts/:id" }] as const;

// 定义ROUTES的类型:每个key对应其路径的RouteFunction
type Routes = {
  [K in typeof rawRoutes[number]["key"]]: 
    RouteFunction<Extract<typeof rawRoutes[number], { key: K }>["path"]>
};

function buildRouteFn<T extends string>(path: T): RouteFunction<T> {
  return (...args: string[]) => 
    args.reduce((_path, arg) => _path.replace(/:\w+/, arg), path) as any;
}

// 生成ROUTES并断言为正确的类型
export const ROUTES = rawRoutes.reduce(
  (acc, item) => ({
    ...acc,
    [item.key]: buildRouteFn(item.path),
  }),
  {} as Routes
);

效果说明

  • 调用ROUTES.singlePost()时,TypeScript会提示无参数,返回/posts/:id
  • 调用ROUTES.singlePost("123")时,会提示需要传入id: string参数,返回/posts/123
  • 多参数路由(比如/posts/:id/comments/:commentId)也能自动推断出(id: string, commentId: string) => string的函数类型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:31:07