Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Previously accessible types are no longer accessible from 2.2.6 -> 2.2.7 #4554

Open
JP250552 opened this issue Aug 9, 2024 · 20 comments
Open

Comments

@JP250552
Copy link

JP250552 commented Aug 9, 2024

With the consolidated types change in 2.2.7, certain types are no longer available.
While I understand these may be considered "internal" types, they are really helpful when utilizing a custom base query.

I would ask for your consideration in exposing at minimum the following:

@reduxjs/toolkit/dist/query/baseQueryTypes

  • BaseQueryError
  • BaseQueryMeta

@reduxjs/toolkit/dist/query/endpointDefinitions

  • MutationExtraOptions
  • QueryExtraOptions
  • ResultDescription

As a workaround, it looks like these are available in the src directory.

@markerikson
Copy link
Collaborator

Can you give some examples of where / how you're trying to use these types?

@JP250552
Copy link
Author

JP250552 commented Aug 9, 2024

Yes certainly.

We've created a base query that handles API functions generated from our open api schema. We have some utilities created to make creating fully typed endpoints based on those functions.

Here is an example of where we create a custom EndpointBuilder and QueryExtraOptions to handle queries.

// Extended types

export type CustomEndpointBuilder<T = unknown> = EndpointBuilder<
  BaseQueryFn<QueryCallback<T>>,
  string,
  'api'
>;

export interface CustomQueryExtraOptions<T extends (...args: any) => any>
  extends Omit<
    QueryExtraOptions<
      any,
      BaseQueryReturnType<T>,
      QueryArgs<T>,
      BaseQueryFn<QueryCallback<T>>,
      'api'
    >,
    'type'
  > {
  providesTags?: ResultDescription<
    any,
    BaseQueryReturnType<T>,
    QueryArgs<T>,
    BaseQueryError<BaseQueryFn<QueryCallback<T>>>,
    BaseQueryMeta<BaseQueryFn<QueryCallback<T>>>
  >;
}
// Utility functions for working with custom API functions

export function createQuery(builder: CustomEndpointBuilder) {
  return <T extends (...args: any[]) => QueryCallback>(
    apiFn: T,
    options?: CustomQueryExtraOptions<T>,
  ) =>
    builder.query<BaseQueryReturnType<T>, QueryArgs<T>>({
      ...options,
      query: apiFn,
    });
}

@geril2207
Copy link

I am also using types from @reduxjs/toolkit/dist/query/baseQueryTypes such as QueryReturnValue for some utility functions

@AndreasNH
Copy link

I have a usecase where we use the QueryReturnValue type to create a reposehandler to enrich our logging middleware with metadata.

/**
 * This is a utility for parsing responses from an API that follows the REST API conventions.
 *
 * The metaOpts makes it possible to carry extra info on actions. An example is adding { shouldLog412: true } so that
 * the error logging middleware is able to know if API errors should be logged or not.
 *
 * @param resultPromise The result
 * @param metaOpts      These options end up on the response
 */
export const handleResponse = <T, MetaOpts>(
  resultPromise: Promise<JsonQuery<Resultstash<T>>>,
  metaOpts?: MetaOpts,
): Promise<QueryReturnValue<Resultstash<T>, BaseQueryError<any>, QueryMeta<MetaOpts>>> => {
  return resultPromise.then(
    (query) => {
      const { response, request, json } = query;

      if (response.ok) {
        return {
          data: json,
          meta: { response: serializeResponse(response), request: serializeRequest(request), metaOpts },
        };
      } else {
        return {
          error: responseToError(query),
          meta: { response: serializeResponse(response), request: serializeRequest(request), metaOpts },
        };
      }
    },
    (err) => {
      return {
        error: normalizedError(err),
      };
    },
  );
};

// Mock useage of handleResponse
const fetchTextBlobFn = (build: EndpointBuilder<InternalFetchBaseQuery, BaseApiTagTypes, "api">) =>
  build.mutation<
    IResultstash<TextBlob>,
    { params: FetchCriteria; metaOpts?: QueryMeta["metaOpts"] }
  >({
    queryFn: ({ params, metaOpts }, api) =>
      handleResponse(
        fetchTextBlob(params),
        metaOpts,
      ),
  });

export const api = baseApi.injectEndpoints({
  endpoints: (build) => ({
    fetchText: fetchTextBlobFn(build),
  }),
});

@arthurmmedeiros
Copy link

I was also using MutationLifecycleApi and QueryLifecycleApi from @reduxjs/toolkit/dist/query/endpointDefinitions for some utility functions. I have some endpoints that share the same logic in onQueryStarted, and having these types available let me write a single function to be passed to onQueryStarted.

Any chance to have these types exported again?

@jamesmontalvo3
Copy link

We were using:

import type { AsyncThunk, BaseThunkAPI } from "@reduxjs/toolkit/dist/createAsyncThunk";

@EskiMojo14
Copy link
Collaborator

@jamesmontalvo3 AsyncThunk is already exported, how were you using BaseThunkAPI?

@jamesmontalvo3
Copy link

@EskiMojo14 I was using it to create a wrapper on createAsyncThunk called appCreateAsyncThunk that provides the app's RootState, AppDispatch, etc. I think I've cleaned it up to use exports from @reduxjs/toolkit without reaching into /dist.

@EskiMojo14
Copy link
Collaborator

@jamesmontalvo3 have you seen createAsyncThunk.withTypes()?

@jamesmontalvo3
Copy link

I had not. Thanks!

Inclusion of the rejectValue in the reusable function seems strange. Each thunk could have different rejected values.

@EskiMojo14
Copy link
Collaborator

it's just giving the example of possible thunk config options, i agree you're not likely to specify rejectValue there 😛

@kokchuankoh
Copy link

Would it also be possible to expose the type definition LazyQueryTrigger that was exported from @reduxjs/toolkit/dist/query/react/buildHooks ? LazyQueryTrigger is the type defintion for fetchTrigger returned by useLazy...Query functions.

I tried pointing the type definition to @reduxjs/toolkit/src/query/react/buildHooks, but I'll get a type error in line 848 of @reduxjs/toolkit/src/query/react/buildHooks . The error message is 'This comparison appears to be unintentional because the types '"development" | "production" | "test"' and '"removeMeOnCompilation"' have no overlap.'

Thank you

@markerikson
Copy link
Collaborator

@kokchuankoh possibly, but can you show an example of where / how / why you need to use that type?

@EskiMojo14
Copy link
Collaborator

@kokchuankoh we export a TypedLazyQueryTrigger type instead.

export type TypedLazyQueryTrigger<
ResultType,
QueryArg,
BaseQuery extends BaseQueryFn,
> = LazyQueryTrigger<

@kokchuankoh
Copy link

kokchuankoh commented Sep 9, 2024

@markerikson Sure, I have components that use a custom type named LookupPersonSearchProps . That prop type definition is as follows:

.....
import { LazyQueryTrigger } from '@reduxjs/toolkit/dist/query/react/buildHooks';
import {
  BaseQueryFn,
  FetchArgs,
  FetchBaseQueryError,
  FetchBaseQueryMeta,
  QueryDefinition,
} from '@reduxjs/toolkit/query';

export interface LookupPersonSearchProps {
  data?: EmployeeFilters;
  /**
   * Will be executed when the primary button is pressed
   */
  getData: LazyQueryTrigger<
    QueryDefinition<
      EmployeeFilters,
      BaseQueryFn<
        string | FetchArgs,
        unknown,
        FetchBaseQueryError,
        object,
        FetchBaseQueryMeta
      >,
      'Employee' | 'Department',
      EmployeeListReponse,
      'lookupsApi'
    >
  >;
  /**
   * Will be executed when the secondary button is pressed
   */
  callbackfunction: Dispatch<SetStateAction<string>>;
  /**
   * Will be executed when either button is pressed
   */
  handleClose: () => void;
}
.....

From a parent component, I referenced the lazy version of a rtk basequery and passed a fetchTrigger function to children components as follows:

.....
  const [fetchTrigger, { data, error, isFetching }] = useLazyGetemployeeQuery( {} );
.....

switch (nextStep) {
    case 'Child component1':
      component = (
        <ChildComponent1
          getData={fetchTrigger}
          handleClose={onClose}
          callbackfunction={setnextStep}
        />
      );
      break;
    case 'Child component2':
      component = (
        <ChildComponent2
          getData={fetchTrigger}
          handleClose={onClose}
          callbackfunction={setnextStep}
        />
      );
      break;
    ....
    default:
      component = <NotFound />;
  }

@EskiMojo14
Copy link
Collaborator

@kokchuankoh

getData: TypedLazyQueryTrigger<
      EmployeeListResponse,
      EmployeeFilters,
      ReturnType<typeof fetchBaseQuery>
    >
  >;

@kokchuankoh
Copy link

@kokchuankoh

getData: TypedLazyQueryTrigger<
      EmployeeListResponse,
      EmployeeFilters,
      ReturnType<typeof fetchBaseQuery>
    >
  >;

That worked. Thanks so much @EskiMojo14 !

@jakubjochymek
Copy link

hey, do you have any solution to "QueryReturnValue" ? anything i can use instead?

@geril2207
Copy link

geril2207 commented Sep 17, 2024

hey, do you have any solution to "QueryReturnValue" ? anything i can use instead?

Downgrade to 2.2.6(imo the most convinient) untill it has been resolved or something like ReturnType<ReturnType<typeof fetchBaseQuery>> but you can't use it as a generic

@EskiMojo14
Copy link
Collaborator

i don't think we'd be against a PR adding QueryReturnValue to our exports, it's a pretty simple type (and is actually detailed in our docs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants