在我的应用程序中,我有这样一个路由对象:

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 --- ERROR
  return fetch(routes[route](...params));
}

// This part actually works
get('home');
get('user', { userId: '1' });

我的问题是,当我生成get函数时,会出现类型错误.我不太确定如何处理传递参数的问题,就像每当我试图以这样或那样的方式扭曲它时,我要么得到另一个错误,要么没有类型帮助.我可以用ofc.断言...params[any],它可以工作,但希望找到一个没有任何参数的解决方案.我的GetParams助手是否返回元组?

提前感谢!:)

推荐答案

这里的问题涉及我所说的"相关联",如microsoft/TypeScript#30581中所述.编译器将routes[route]视为泛型类型constrainedunion type (() => string) | (x: {userId: string}) => string)的值,并将params视为约束到联合类型[] | [x: {userId: string}]的泛型类型的值.We知道或期望routes[route]的类型是correlatedparams的类型是correlated,因此前者是() => string,当且仅当后者是[].但是编译器不知道这一点;令人担忧的是,可能params将是[],但routes[route]将是(x: {userId: string}) => string,这将是不好的(当传递零参数时,期望{userId: string}的函数将不满意).

特定的错误消息令人困惑,因为它抱怨元组类型,但潜在的问题是它不允许您调用函数的并集和相关参数类型的并集.


microsoft/TypeScript#47109所示,这里的修复方法是将routes[route]类型写为distributive object type,这是一个mapped type,您可以立即将index写入其中.看起来是这样的:

function get<P extends keyof Routes>(
  route: P, ...params: Parameters<Routes[P]>
) {
  const r: { [K in keyof Routes]:
    (...params: Parameters<Routes[K]>) => string
  }[P] = routes[route];
  return fetch(r(...params)); // okay
}

这里我们将变量r设置为routes[route].但至关重要的是,我们有annotated它是一个分布式对象类型,其中r被视为映射类型的键P处的属性,其中Routes的每个键K映射到其参数列表为Parameters<Routes[K]>类型的函数(使用the Parameters<T> utility type).即使"更简单"的版本const r: (...params: Parameters<Routes[P]>) => string = routes[route]没有编译,它也会编译.这与原始版本在联合体中的分布方式有关.详见ms/TS#47const r: (...params: Parameters<Routes[P]>) => string = routes[route].

现在编译器允许您调用r(...params),因为paramsParameters<Routes[P]>类型!

Playground link to code

Typescript相关问答推荐

Typescript:假设foo不在类型栏中,而它在:如何调试

如何使用Generics保留构造函数的类型信息?

如何在TypeScript对象迭代中根据键推断值类型?

在这种情况下,如何获得类型安全函数的返回值?

TypeScript实用程序类型—至少需要一个属性的接口,某些指定属性除外

属性的类型,该属性是类的键,其值是所需类型

如何根据模板类型实现不同的模板函数行为?

使用打字Angular 中的通用数据创建状态管理

有没有可能产生输出T,它在视觉上省略了T中的一些键?

如何使所有可选字段在打印脚本中都是必填字段,但不能多或少?

ANGLING v17 CLI默认设置为独立:延迟加载是否仍需要@NgModule进行路由?

如何使用模板继承从子组件填充基础组件的画布

TypeScrip:从对象中提取和处理特定类型的键

是否可以强制静态方法将同一类型的对象返回其自己的类?

错误:NG02200:找不到类型为';对象';的其他支持对象';[对象对象]';.例如数组

如何在打字角react 式中补齐表格组

如何从上传文件中删除预览文件图标?

为什么过滤器不改变可能的类型?

传入类型参数<;T>;变容函数

在Typescript 无法正常工作的 Three.js 中更新动画中的 GLSL 统一变量