【问题标题】:TypeScript: How to type react-query useMutation onError with generic?TypeScript:如何使用泛型输入 react-query useMutation onError?
【发布时间】:2021-11-29 12:17:36
【问题描述】:

考虑一个自定义的useSignUp 钩子,其中mutate() 函数需要一些字段(在此示例中为nameemail):

export default function App() {
  const name = "David";
  const email = "david@gmail.com";
  const signupMutation = useSignUp();

  return (
    <button
      onClick={() => {
        signupMutation.mutate(
          { name, email },
          {
            onSuccess: (result) => {
              ...
            },
            onError: (result) => {
              // Wanted: result of type ErrorResult<"name" | "email">
            }
          }
        );
      }}
    >
      Sign Up
    </button>
  );
}

在这种情况下,我希望onError 的结果为ErrorResponse&lt;"name" | "email"&gt; 类型。但是,我得到了ErrorResponse&lt;string&gt;

这是为什么呢?我如何指示 TypeScript 根据传递的数据推断特定类型(即"name" | "email",而不是string)?

这是我输入useSignUp的方式:

type SuccessResponse = {
  userId: string;
};

type ErrorResponse<T> = {
  userId?: string;
  formErrors?: Array<{
    field: T;
    type: string;
  }>;
};

export const useSignUp = <T extends string>() => {
  return useMutation<SuccessResponse, ErrorResponse<T>, Record<T, string>>(
    (data) => {
      return new Promise((resolve, reject) => {
        // Some logic here to either return a success or an error response
        if (Math.random() > 0.5) {
          resolve({
            userId: "1234"
          });
        } else {
          reject({
            formErrors: [
              {
                field: "email", // I want TypeScript to complain if it's neither "name" nor "email"
                type: "ALREADY_EXISTS"
              }
            ]
          });
        }
      });
    }
  );
};

【问题讨论】:

  • 关于你的reject签名,参数不能更改。请参阅this 答案。
  • @MishaMoroshko 你能提供可重现的例子吗?

标签: reactjs typescript react-hooks typescript-generics react-query


【解决方案1】:

你已经声明了一个带有通用错误字段的钩子,如果你不提供参数,它默认为一个字符串:

export const useSignUp = <T extends string>() => {
  return useMutation<SuccessResponse, ErrorResponse<T>, Record<T, string>>(...)
}

所以一定要覆盖它:

type Field = 'name' | 'email';

// ...

useSignUp<Field>();

如果要根据提交的值键入错误:

const mutatedValues = {
  name: "David",
  email: "david@gmail.com"
};
const signupMutation = useSignUp<keyof typeof mutatedValues>();
onError: (result) => {
  result.formErrors?.forEach((e) => {
    const { field } = e; // field is 'name' | 'email'
  });
}

【讨论】:

  • 是否可以避免将泛型提供给useSignUp,而让TypeScript 以某种方式提供给infer
  • @MishaMoroshko 理论上,我认为 Typescript 可以通过使来自 react-querymutate() 函数知道数据的关键,基于 mutatedValues 推断 onError 回调的参数,但图书馆不支持它。它们只允许您单独覆盖 TDataTError
  • 需要在 useMutation 调用中定义类型。你不能让 useMutation 根据你最终传递给mutate 的内容来推断它的类型。要么按照此处的建议显式传递泛型,要么进行与用户名/电子邮件相关的特定突变(无泛型),或者将字段直接传递给 useMutation(如果可用),以便您可以从中推断:const signupMutation = useSignUp({ name, email });。然后,您可以在没有参数的情况下调用.mutate(),并关闭您传递给 useMutation 的内容。然后,推理应该起作用了。
猜你喜欢
  • 2022-06-22
  • 2021-03-09
  • 2022-06-16
  • 2022-11-01
  • 1970-01-01
  • 2023-04-08
  • 2023-01-24
  • 2021-04-15
  • 2021-11-05
相关资源
最近更新 更多