兄弟函数的泛型参数的打字稿推断 [英] Typescript inference of sibling function's generic arguments

查看:30
本文介绍了兄弟函数的泛型参数的打字稿推断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现以下推断:

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.

请告诉我哪种方法更正确,以及如何调整它以实现variablesdata推理.或者也许还有另一种我没有考虑过的方法.提前致谢!

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆