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

TypeScript如何正确定义返回路由的函数对象类型

问题复现

在应用中定义如下路由对象与路由请求方法时,get函数内部出现类型报错:

const routes = {
  home: () => '/',
  user: ({ userId }: { userId: string }) => `/user/${userId}`,
} as const;

type Routes = typeof routes;
type RoutesKey = keyof Routes;

type GetParams<Key extends RoutesKey> = Parameters<
  Routes[Key]
>[0] extends undefined
  ? [undefined?]
  : [Parameters<Routes[Key]>[0]];

function get<Path extends RoutesKey>(route: Path, ...params: GetParams<Path>) {
  // 此处报错:...params must be a tuple or passed as a rest parameter
  return fetch(routes[route](...params));
}

// 函数调用侧的类型提示是正常的
get('home');
get('user', { userId: '1' });

调整类型定义的过程中,要么出现新的类型错误,要么丢失类型提示,不希望使用any类型断言绕过问题,疑惑GetParams辅助类型是否未正确返回元组类型。

报错原因

你定义的GetParams在传入具体的单一路由key(比如'home'、'user')时,确实会返回正确的元组类型,这也是函数调用侧类型提示正常的原因。
但在get函数内部,泛型Path是RoutesKey的子类型,在未被窄化到单个具体字面量类型时,TypeScript 不会对条件类型做分布式求值,此时GetParams<Path>会被推导为联合元组类型[undefined?] | [{ userId: string }],TS 无法建立参数和对应路由函数的关联校验,会认为联合元组不能直接作为剩余参数展开传入函数,因此抛出错误。

解决方案

不需要自定义GetParams类型,直接使用TypeScript内置的Parameters工具类型获取路由函数的原始参数元组即可,函数内部仅需做极小范围的类型断言(完全类型安全,不涉及any):

const routes = {
  home: () => '/',
  user: ({ userId }: { userId: string }) => `/user/${userId}`,
} as const;

type Routes = typeof routes;
type RoutesKey = keyof Routes;

function get<Path extends RoutesKey>(
  route: Path,
  ...params: Parameters<Routes[Path]>
) {
  // 仅将路由函数断言为接收对应参数的同签名函数,无类型安全问题
  const routeHandler = routes[route] as (...args: Parameters<Routes[Path]>) => string;
  return fetch(routeHandler(...params));
}

// 调用侧类型校验完全正常
get('home'); // 正常
get('user', { userId: '1' }); // 正常
// 错误传参会被TS精准拦截
// get('home', {}) // 报错:home路由不需要参数
// get('user') // 报错:缺少userId参数
// get('user', { userId: 123 }) // 报错:userId类型不匹配

这个方案完全保留了调用侧的类型提示,没有使用any绕过校验,内部的断言是安全的:因为函数入口已经通过泛型约束保证了传入参数和路由key的匹配,内部只是帮TS确认了这个对应关系。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:06:10