From 35389af6a59ff5d3f524d937eddbe9e4696a37b0 Mon Sep 17 00:00:00 2001 From: liaoxuan Date: Sun, 18 Feb 2024 15:53:50 +0800 Subject: [PATCH] fix: mutate requires arguments if middleware is used --- README-zh_CN.md | 60 ++++++++++++++++++++++++++++++++++++++++--------- README.md | 60 ++++++++++++++++++++++++++++++++++++++++--------- src/types.ts | 12 +++++----- 3 files changed, 106 insertions(+), 26 deletions(-) diff --git a/README-zh_CN.md b/README-zh_CN.md index d1c3a54..079daff 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -48,6 +48,7 @@ - [createMutation](#createmutation) - [router](#router) - [中间件](#中间件) + - [TypeScript](#typescript) - [类型推导](#类型推导) - [常见问题](#常见问题) - [迁移](#迁移) @@ -83,12 +84,12 @@ $ yarn add react-query-kit import { QueryClient, dehydrate } from '@tanstack/react-query' import { createQuery } from 'react-query-kit' -type Response = { title: string; content: string } +type Data = { title: string; content: string } type Variables = { id: number } const usePost = createQuery({ queryKey: ['posts'], - fetcher: (variables: Variables): Promise => { + fetcher: (variables: Variables): Promise => { return fetch(`/posts/${variables.id}`).then(res => res.json()) }, // 你还可以通过中间件来定制这个 hook 的行为 @@ -140,7 +141,7 @@ const queries = useQueries({ }) // getQueryData -queryClient.getQueryData(usePost.getKey(variables)) // Response +queryClient.getQueryData(usePost.getKey(variables)) // Data // setQueryData queryClient.setQueryData(usePost.getKey(variables), {...}) @@ -175,12 +176,12 @@ Expose Methods import { QueryClient, dehydrate } from '@tanstack/react-query' import { createInfiniteQuery } from 'react-query-kit' -type Response = { projects: { id: string; name: string }[]; nextCursor: number } +type Data = { projects: { id: string; name: string }[]; nextCursor: number } type Variables = { active: boolean } const useProjects = createInfiniteQuery({ queryKey: ['projects'], - fetcher: (variables: Variables, { pageParam }): Promise => { + fetcher: (variables: Variables, { pageParam }): Promise => { return fetch( `/projects?cursor=${pageParam}?active=${variables.active}` ).then(res => res.json()) @@ -478,7 +479,7 @@ Expose Methods import { QueryClient } from '@tanstack/react-query' import { Middleware, MutationHook, QueryHook, getKey } from 'react-query-kit' -const logger: Middleware> = useQueryNext => { +const logger: Middleware> = useQueryNext => { return options => { const log = useLogger() const fetcher = (variables, context) => { @@ -493,7 +494,7 @@ const logger: Middleware> = useQueryNext => { } } -const useUser = createQuery({ +const useUser = createQuery({ use: [logger], }) @@ -593,6 +594,45 @@ const useSomething = createQuery({ useSomething({...}, anotherQueryClient) ``` +## TypeScript + +默认情况下,ReactQueryKit 还会从 `fetcher` 推断 `data` 和 `variables` 的类型,因此您可以自动获得首选类型。 + +```ts +type Data = { title: string; content: string } +type Variables = { id: number } + +const usePost = createQuery({ + queryKey: ['posts'], + fetcher: (variables: Variables): Promise => { + return fetch(`/posts/${variables}`).then(res => res.json()) + }, +}) + +// `data` 将被推断为 `Data | undefined`. +// `variables` 将被推断为 `Variables`. +const { data } = usePost({ variables: 1 }) +``` + +您还可以显式指定 `fetcher` 参数和返回的类型。 + +```ts +type Data = { title: string; content: string } +type Variables = { id: number } + +const usePost = createQuery({ + queryKey: ['posts'], + fetcher: variables => { + return fetch(`/posts/${variables}`).then(res => res.json()) + }, +}) + +// `data` 将被推断为 `Data | undefined`. +// `error` 将被推断为 `Error | null` +// `variables` 将被推断为 `Variables`. +const { data, error } = usePost({ variables: 1 }) +``` + ## 类型推导 您可以使用 `inferData` 或 `inferVariables` 提取任何自定义 hook 的 TypeScript 类型 @@ -600,10 +640,10 @@ useSomething({...}, anotherQueryClient) ```ts import { inferData, inferFnData, inferError, inferVariables, inferOptions } from 'react-query-kit' -const useProjects = createInfiniteQuery(...) +const useProjects = createInfiniteQuery(...) -inferData // InfiniteData -inferFnData // Response +inferData // InfiniteData +inferFnData // Data inferVariables // Variables inferError // Error inferOptions // InfiniteQueryHookOptions<...> diff --git a/README.md b/README.md index 7e5b489..1e50ea9 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ English | [简体中文](./README-zh_CN.md) - [createMutation](#createmutation) - [router](#router) - [Middleware](#middleware) + - [TypeScript](#typescript) - [Type inference](#type-inference) - [FAQ](#faq) - [Migration](#migration) @@ -86,12 +87,12 @@ If you still on React Query Kit v2? Check out the v2 docs here: https://github.c import { QueryClient, dehydrate } from '@tanstack/react-query' import { createQuery } from 'react-query-kit' -type Response = { title: string; content: string } +type Data = { title: string; content: string } type Variables = { id: number } const usePost = createQuery({ queryKey: ['posts'], - fetcher: (variables: Variables): Promise => { + fetcher: (variables: Variables): Promise => { return fetch(`/posts/${variables.id}`).then(res => res.json()) }, // u can also pass middleware to cutomize this hook's behavior @@ -142,7 +143,7 @@ const queries = useQueries({ }) // getQueryData -queryClient.getQueryData(usePost.getKey(variables)) // Response +queryClient.getQueryData(usePost.getKey(variables)) // Data // setQueryData queryClient.setQueryData(usePost.getKey(variables), {...}) @@ -177,12 +178,12 @@ Expose Methods import { QueryClient, dehydrate } from '@tanstack/react-query' import { createInfiniteQuery } from 'react-query-kit' -type Response = { projects: { id: string; name: string }[]; nextCursor: number } +type Data = { projects: { id: string; name: string }[]; nextCursor: number } type Variables = { active: boolean } const useProjects = createInfiniteQuery({ queryKey: ['projects'], - fetcher: (variables: Variables, { pageParam }): Promise => { + fetcher: (variables: Variables, { pageParam }): Promise => { return fetch( `/projects?cursor=${pageParam}?active=${variables.active}` ).then(res => res.json()) @@ -478,7 +479,7 @@ Middleware receive the hook and can execute logic before and after running it. I import { QueryClient } from '@tanstack/react-query' import { Middleware, MutationHook, QueryHook, getKey } from 'react-query-kit' -const logger: Middleware> = useQueryNext => { +const logger: Middleware> = useQueryNext => { return options => { const log = useLogger() const fetcher = (variables, context) => { @@ -493,7 +494,7 @@ const logger: Middleware> = useQueryNext => { } } -const useUser = createQuery({ +const useUser = createQuery({ use: [logger], }) @@ -593,6 +594,45 @@ const useSomething = createQuery({ useSomething({...}, anotherQueryClient) ``` +## TypeScript + +By default, ReactQueryKit will also infer the types of `data` and `variables` from `fetcher`, so you can have the preferred types automatically. + +```ts +type Data = { title: string; content: string } +type Variables = { id: number } + +const usePost = createQuery({ + queryKey: ['posts'], + fetcher: (variables: Variables): Promise => { + return fetch(`/posts/${variables}`).then(res => res.json()) + }, +}) + +// `data` will be inferred as `Data | undefined`. +// `variables` will be inferred as `Variables`. +const { data } = usePost({ variables: 1 }) +``` + +You can also explicitly specify the types for `fetcher`‘s `variables` and `data`. + +```ts +type Data = { title: string; content: string } +type Variables = { id: number } + +const usePost = createQuery({ + queryKey: ['posts'], + fetcher: variables => { + return fetch(`/posts/${variables}`).then(res => res.json()) + }, +}) + +// `data` will be inferred as `Data | undefined`. +// `error` will be inferred as `Error | null` +// `variables` will be inferred as `Variables`. +const { data, error } = usePost({ variables: 1 }) +``` + ## Type inference You can extract the TypeScript type of any custom hook with `inferData` or `inferVariables` @@ -600,10 +640,10 @@ You can extract the TypeScript type of any custom hook with `inferData` or `infe ```ts import { inferData, inferFnData, inferError, inferVariables, inferOptions } from 'react-query-kit' -const useProjects = createInfiniteQuery(...) +const useProjects = createInfiniteQuery(...) -inferData // InfiniteData -inferFnData // Response +inferData // InfiniteData +inferFnData // Data inferVariables // Variables inferError // Error inferOptions // InfiniteQueryHookOptions<...> diff --git a/src/types.ts b/src/types.ts index f50e113..258f08d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -445,15 +445,15 @@ export interface CreateMutationOptions< TError = CompatibleError, TContext = unknown > extends UseMutationOptions { - use?: Middleware>[] + use?: Middleware>[] } export interface MutationHookOptions extends Omit< - UseMutationOptions, + UseMutationOptions, 'mutationFn' | 'mutationKey' > { - use?: Middleware>[] + use?: Middleware>[] } export type MutationHookResult< @@ -466,7 +466,7 @@ export type MutationHookResult< export interface ExposeMutationMethods< TData = unknown, TVariables = void, - TError = unknown, + TError = CompatibleError, TDefaultContext = unknown > { getKey: () => MutationKey | undefined @@ -482,7 +482,7 @@ export interface ExposeMutationMethods< export interface MutationHook< TData = unknown, TVariables = void, - TError = unknown, + TError = CompatibleError, TDefaultContext = unknown > extends ExposeMutationMethods { ( @@ -593,7 +593,7 @@ export type inferCreateOptions = T extends QueryHook< infer TError, infer TContext > - ? CreateMutationOptions + ? CreateMutationOptions : never // router