兄弟函数的泛型参数的打字稿推断 [英] Typescript inference of sibling function's generic arguments
问题描述
我想实现以下推断:
type RequestAction<Data = any, TransformedData = Data> = {
type: string;
request: any | any[];
meta?: {
getData?: (data: Data, currentData: TransformedData) => TransformedData;
[extraProperty: string]: any;
};
};
function fetchBooks(
x: number,
y: string,
): RequestAction<{ raw: boolean }, { parsed: boolean }> {
return {
type: 'FETCH_BOOKS',
request: {
url: '/books',
x,
y,
},
meta: {
getData: data => ({ parsed: data.raw }),
},
};
}
const query = useQuery({
action: fetchBooks,
variables: [1, '2'], // inferred from fetchBooks argument types
});
query.data // inferred from `fetchBooks` generic
我只能同时实现一个,而不能同时实现.这是我的尝试:
I can achieve only one at the same time, never both. Here are my attempts:
1)
interface QueryState<QueryStateData> {
data: QueryStateData;
error: any;
loading: boolean;
}
type Arr = readonly any[];
export function useQuery<
QueryStateData = any,
Variables extends Arr = any
>(props: {
action?: (...args: Variables) => RequestAction<any, QueryStateData>;
variables?: Variables;
}): QueryState<QueryStateData>;
这几乎有效,data
是从传递给 fetchBooks:RequestAction 的 QueryStateData
自动推断出来的.变量也部分起作用,但只是部分起作用.它似乎工作正常,例如如果 fetchBooks
参数是 (string, number)
,则 variables
的类型确实是 [字符串,数字]
元组.但是由于某种原因,如果我设置 variables: [1, '1']
,那么它仍然可以工作,因为 TS 突然输入的是 (string | number)[]
,将其转换为联合数组,原因我不知道,这是不可接受的,我希望变量是精确的 action
参数,顺序敏感.
This almost works, data
is inferred automatically from QueryStateData
passed to fetchBooks: RequestAction. Variables also partially work, but only partially. It seems to work fine, for example if fetchBooks
arguments is (string, number)
, then type for variables
will be indeed [string, number]
tuple. But for some reason if I set variables: [1, '1']
, then it would still work as suddenly type from TS would be (string | number)[]
, converting it to array of unions, for reason unknown to me, which is unacceptable, I want variables to be precisely action
arguments, order sensitive.
2)
interface RequestCreator<QueryStateData> {
(...args: any[]): RequestAction<any, QueryStateData>;
}
export function useQuery<
QueryStateData = any,
R extends RequestCreator<QueryStateData> = RequestCreator<QueryStateData>
>(props: {
action?: R;
variables?: Parameters<R>;
}): QueryState<QueryStateData>;
虽然我可以实现完美的 variables
推理.不幸的是,query.data
将是 any
的类型,QueryStateData
推断在这种情况下由于某种原因不起作用,它不是从 <代码>动作代码>回调通用.
With this one though I can achieve perfect variables
inference. Unfortunately query.data
would be type of any
, QueryStateData
inference doesn't work for some reason in this case, it is not picked from action
callback generic.
请告诉我哪种方法更正确,以及如何调整它以实现variables
和data
推理.或者也许还有另一种我没有考虑过的方法.提前致谢!
Please tell me which method is more correct, and how to adjust it to achieve both variables
and data
inference. Or maybe there is yet another method I didn't consider. Thanks in advance!
推荐答案
尝试对操作使用单个类型参数,这与您的第二次尝试类似.
Try using a single type parameter for the action, which is similar to your second attempt.
interface RequestCreator<QueryStateData = any> {
(...args: any[]): RequestAction<any, QueryStateData>;
}
// Gets the `QueryStateData` type from a `RequestCreator`
// (e.g. GetQueryStateData<typeof fetchBooks> is { parsed: boolean }).
type GetQueryStateData<T extends RequestCreator> = T extends RequestCreator<infer QueryStateData>
? QueryStateData
: never;
// I'm just using declare here so TS is happy
export declare function useQuery<R extends RequestCreator>(props: {
action?: R;
// The parameter types of R
// (e.g. Parameters<typeof fetchBooks> is [x: number, y: string])
variables?: Parameters<R>;
}): QueryState<GetQueryStateData<R>>;
const query = useQuery({
action: fetchBooks,
variables: [1, '2'],
});
// inferred correctly as { parsed: boolean }
query.data;
useQuery({
action: fetchBooks,
// Type 'number' is not assignable to type 'string'. (expected)
variables: [1, 1],
});
我认为(基于轶事经验;请不要在这方面引用我的话)当 TypeScript 直接对应于参数类型(或直接包含"在其中的类型,例如 的类型)时,它们会更好地推断类型参数动作
).这就是编译器在您第二次尝试时无法推断 QueryStateData
类型的原因.
I think (based on anecdotal experience; please don't quote me on this) that TypeScript infers type parameters better when they directly correspond to parameter types (or types directly ‘contained’ in them, like the type of action
). This is why the compiler was having trouble inferring the type of QueryStateData
in your second attempt.
这篇关于兄弟函数的泛型参数的打字稿推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!