我正在尝试构建一个通用的"req"函数,该函数接受URL路径(字符串)和对象(GET/POST参数)作为参数,并返回具有适当推断类型的结果。
这将是我的函数获取其类型定义的接口:
interface ValidQueries{
books: (q: {
limit?: number;
category?: string;
}) => Book[];
authors: (q: {
name?: string;
}) => Author[];
}
并尝试编写函数:
const req = <K extends keyof ValidQueries>(path: string, params: (Parameters<ValidQueries[K]>[0])) => {
return useQuery([path, params], ({ queryKey }) => {
const [, params] = queryKey;
return httpRequest(path, params) as Promise<ReturnType<ValidQueries[K]>>;
});
};
示例:req("books", { limit: 10 });
-〉返回类型应该显示为Book [],第二个arg应该显示为接口中匹配函数的"q"类型。params
类型定义似乎不正确。2我想从接口(q)的函数中获取第一个参数的类型。
返回类型Promise<ValidQueries[K]>
可以工作,但它并不理想,因为我看到了所有可能的类型,比如Book[] | Author[]
,而不是如果我将"books"作为第一个参数传递时只看到Book[]
,或者如果我将"authors"作为第一个参数传递时只看到Author[]
...
1条答案
按热度按时间ercv8c1e1#
最重要的是,当你使用泛型时,你需要有一些锚,TypeScript可以从中推断。在这个函数中,你使用
path: string
(所以任何字符串),而使用泛型K
的唯一参数是params
。正因为如此,当你调用
req("books", { limit: 10 })
时,为了计算泛型K
,它会做类似Extract<ValidQueries[keyof ValidQueries], { limit: 10 }>
的事情。为了解决这个问题,你可以使用K
作为路径参数-path: K
。这将有助于从ValidQueries
中找到合适的方法。它还应该解决
Book[] | Author[]
的问题,除非useQuery
有不正确的类型(然后您可以将as …
子句推到末尾,或者直接键入函数返回类型)。此外,您可以使用像
...params: Parameters<…>
这样的rest参数,因此它将允许向下传递任意数量的ValidQueries[K]
参数,还将把q:
名称添加到IDE中的参数中,这正是您所期望的。总结一下,你有这样的东西:
不过有一个小的调整,
T
类型在这里是自动创建的,作为一个别名,你可以使用完整的Parameters<ValidQueries[K]>
形式(对于返回类型也是类似的)。