繁体   English   中英

如何正确键入返回路由的函数对象?

[英]How to correctly type an object of functions returning routes?

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

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 函数时,我得到了类型错误。 我不确定如何处理传递参数,就像每当我试图以一种或另一种方式扭曲它时,我都会得到另一个错误或没有类型帮助。 我可以。 断言 ...params [any],它会起作用,但想找到一个没有任何解决方案的解决方案。 我的 GetParams 助手确实返回了一个元组?

提前致谢! :)

这里的问题涉及我所说的“相关联合”,如microsoft/TypeScript#30581中所述。 编译器将routes[route]视为受限联合类型(() => string) | (x: {userId: string}) => string)的泛型类型的值。 (() => string) | (x: {userId: string}) => string) ,它把params看作是一个泛型类型的值,约束为联合类型[] | [x: {userId: string}] [] | [x: {userId: string}] 我们知道或期望routes[route]的类型params的类型相关,因此前者是() => string当且仅当后者是[] 但是编译器不知道这一点; 担心params可能会是[]routes[route]会是(x: {userId: string}) => string ,这会很糟糕(期望{userId: string}的函数在传递零时会不开心参数)。

特定的错误消息令人困惑,因为它抱怨元组类型,但潜在的问题是它不希望允许您调用具有关联参数类型的联合的函数联合。


正如microsoft/TypeScript#47109中所建议的,此处的修复方法是将routes[route]的类型编写为分布式对象类型,这是您立即索引映射类型 它看起来像这样:

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] 但至关重要的是,我们已将其注释为分布式对象类型,其中r被视为映射类型的键P处的属性,其中Routes的每个键K都映射到参数列表类型为Parameters<Routes[K]>的函数Parameters<Routes[K]> (使用Parameters<T>实用程序类型)。 即使“更简单”的版本const r: (...params: Parameters<Routes[P]>) => string = routes[route]没有,这也会编译。 它与原始版本在工会之间的分布方式有关。 有关详细信息,请参阅 ms/TS#47109。

现在编译器愿意让你调用r(...params) ,因为params的类型是Parameters<Routes[P]>

Playground 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM