如何将 RTKQuery queryFn 与 TypeScript 结合使用

问题描述 投票:0回答:2

注意:现在它在 RTKQuery v2 中运行良好,因为它已被重写为 TypeScript。下面是原始问题。


简短描述

我正在尝试编译下面的 TypeScript 代码。

Tsc
对 queryFn 函数的返回类型不满意。我是做错了什么还是错过了什么?

代码

import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query/fetchBaseQuery';
import { baseApi } from '../../../api/baseApi';
import { RootState } from '../../../redux/store';
import { UserResponse } from './userApiTypes';

export const extendedApi = baseApi.injectEndpoints({
    endpoints: build => ({
        getUser: build.query<UserResponse, void>({
            queryFn: async (arg, api, extraOptions, baseQuery) => {
                const state = api.getState() as RootState;

                if (!state.auth.loginToken && !state.auth.refreshToken)
                    return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } as FetchBaseQueryError };

                return await baseQuery(`/user/me`);
            },
        }),
    }),
});

export const { useGetUserQuery, useLazyGetUserQuery } = extendedApi;

错误

Type '(arg: void, api: BaseQueryApi, extraOptions: any, baseQuery: (arg: string | FetchArgs) => Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>) => Promise<...>' is not assignable to type '(arg: void, api: BaseQueryApi, extraOptions: any, baseQuery: (arg: string | FetchArgs) => Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>) => MaybePromise<...>'.
  Type 'Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>' is not assignable to type 'MaybePromise<QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>>'.
    Type 'Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>' is not assignable to type 'PromiseLike<QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>>'.
      Types of property 'then' are incompatible.
        Type '<TResult1 = QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>, TResult2 = never>(onfulfilled?: ((value: QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>) => TResult1 | PromiseLike<...>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | ... 1 more ......' is not assignable to type '<TResult1 = QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>, TResult2 = never>(onfulfilled?: ((value: QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>) => TResult1 | PromiseLike<...>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | ... 1 more ... | undefined...'.
          Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible.
            Types of parameters 'value' and 'value' are incompatible.
              Type 'QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>' is not assignable to type 'QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>'.
                Type '{ error?: undefined; data: unknown; meta?: FetchBaseQueryMeta | undefined; }' is not assignable to type 'QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>'.
                  Type '{ error?: undefined; data: unknown; meta?: FetchBaseQueryMeta | undefined; }' is not assignable to type '{ error?: undefined; data: UserResponse; meta?: unknown; }'.
                    Types of property 'data' are incompatible.
                      Type 'unknown' is not assignable to type 'UserResponse'.ts(2322)
endpointDefinitions.d.ts(37, 5): The expected type comes from property 'queryFn' which is declared here on type 'Omit<EndpointDefinitionWithQuery<void, (args: string | FetchArgs, api: BaseQueryApi, extraOptions: any) => Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>, UserResponse> & { ...; } & { ...; } & QueryExtraOptions<...>, "type"> | Omit<...>'

不好的解决方法

查看互联网上的示例,当我从

build.query
中删除类型以使此点如下所示时,我可以编译此代码:

getUser: build.query({ // changed here
            queryFn: async (arg, api, extraOptions, baseQuery) => {
                const state = api.getState() as RootState;

                if (!state.auth.loginToken && !state.auth.refreshToken)
                    return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } as FetchBaseQueryError };

                return await baseQuery(`/user/me`);
            },
        }),

但是随后我在代码中到处都失去了强类型,这使得这个解决方法至少引起争议。

typescript react-redux redux-toolkit rtk-query
2个回答
4
投票

我最终得到了这段代码,但我不确定这是否是推荐的方法。为了满足编译器的要求而调用

baseQuery
之后发生了很多事情:

import { baseApi } from '../../../api/baseApi';
import { BaseResponse } from '../../../api/baseApiTypes';
import { RootState } from '../../../redux/store';
import { UserResponse } from './userApiTypes';

export const extendedApi = baseApi.injectEndpoints({
  endpoints: build => ({
    getUser: build.query<UserResponse, void>({
      queryFn: async (arg, api, extraOptions, baseQuery) => {
        const state = api.getState() as RootState;

        if (!state.auth.tokens)
          return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } };

        const result = await baseQuery(`/user/me`);

        if (result.error)
          return { error: result.error };

        const baseResponseWithUser = result.data as BaseResponse<UserResponse>;

        if (!baseResponseWithUser.data)
          return { error: { error: `UNKNOWN_ERROR`, status: `CUSTOM_ERROR` } };

        return { data: baseResponseWithUser.data };
      },
    }),
  }),
});

export const { useGetUserQuery, useLazyGetUserQuery } = extendedApi;

2
投票

我遵循了https://redux-toolkit.js.org/rtk-query/usage-with-typescript#typing-a-basequery所以我有一个

QueryReturnValue
类型

export type QueryReturnValue<T = unknown, E = unknown, M = unknown> =
| {
  error: E
  data?: undefined
  meta?: M
}
| {
  error?: undefined
  data: T
  meta?: M
}

然后在

queryFn
中我执行以下操作来解决 TS 编译错误。

const result = await baseQuery(`/user/me`);
return result as QueryReturnValue<UserResponse, unknown, unknown>;

然后我所做的是创建一个辅助函数以使其不那么冗长。

// Somewhere all api slices can import
export function someHelperForTS<T>(result: QueryReturnValue<unknown, unknown, unknown>) {
    return result as QueryReturnValue<T, unknown, unknown>;
}

// Within queryFn
const result = await baseQuery(`/user/me`);
return someHelperForTS<UserResponse>(result);

我不喜欢它,因为我必须在 build.query (

build.query<UserResponse
) 和 someHelperForTS (
someHelperForTS<UserResponse>
) 中声明相同的响应类型。

© www.soinside.com 2019 - 2024. All rights reserved.