diff --git a/packages/toolkit/src/query/fetchBaseQuery.ts b/packages/toolkit/src/query/fetchBaseQuery.ts index 89f9c68ad6..37f1fdd37f 100644 --- a/packages/toolkit/src/query/fetchBaseQuery.ts +++ b/packages/toolkit/src/query/fetchBaseQuery.ts @@ -105,14 +105,14 @@ function stripUndefined(obj: any) { return copy } -export type FetchBaseQueryArgs = { +export type FetchBaseQueryArgs = { baseUrl?: string prepareHeaders?: ( headers: Headers, api: Pick< BaseQueryApi, 'getState' | 'extra' | 'endpoint' | 'type' | 'forced' - > & { arg: string | FetchArgs }, + > & { arg: string | FetchArgs; extraOptions: ExtraOptions }, ) => MaybePromise fetchFn?: ( input: RequestInfo, @@ -188,7 +188,7 @@ export type FetchBaseQueryMeta = { request: Request; response?: Response } * @param {number} timeout * A number in milliseconds that represents the maximum time a request can take before timing out. */ -export function fetchBaseQuery({ +export function fetchBaseQuery({ baseUrl, prepareHeaders = (x) => x, fetchFn = defaultFetchFn, @@ -200,11 +200,11 @@ export function fetchBaseQuery({ responseHandler: globalResponseHandler, validateStatus: globalValidateStatus, ...baseFetchOptions -}: FetchBaseQueryArgs = {}): BaseQueryFn< +}: FetchBaseQueryArgs = {}): BaseQueryFn< string | FetchArgs, unknown, FetchBaseQueryError, - {}, + ExtraOptions, FetchBaseQueryMeta > { if (typeof fetch === 'undefined' && fetchFn === defaultFetchFn) { @@ -212,7 +212,7 @@ export function fetchBaseQuery({ 'Warning: `fetch` is not available. Please supply a custom `fetchFn` property to use `fetchBaseQuery` on SSR environments.', ) } - return async (arg, api) => { + return async (arg, api, extraOptions) => { const { getState, extra, endpoint, forced, type } = api let meta: FetchBaseQueryMeta | undefined let { @@ -248,6 +248,7 @@ export function fetchBaseQuery({ endpoint, forced, type, + extraOptions, })) || headers // Only set the content-type to json if appropriate. Will not be true for FormData, ArrayBuffer, Blob, etc. diff --git a/packages/toolkit/src/query/tests/fetchBaseQuery.test.tsx b/packages/toolkit/src/query/tests/fetchBaseQuery.test.tsx index e2446d50c2..90b5787c6b 100644 --- a/packages/toolkit/src/query/tests/fetchBaseQuery.test.tsx +++ b/packages/toolkit/src/query/tests/fetchBaseQuery.test.tsx @@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit' import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' import { headersToObject } from 'headers-polyfill' import { HttpResponse, delay, http } from 'msw' +// @ts-ignore import nodeFetch from 'node-fetch' import queryString from 'query-string' import { vi } from 'vitest' @@ -852,6 +853,52 @@ describe('fetchBaseQuery', () => { expect(_forced).toBe(true) expect(_extra).toBe(fakeAuth0Client) }) + + test('can be instantiated with a `ExtraOptions` generic and `extraOptions` will be available in `prepareHeaders', async () => { + const prepare = vitest.fn() + const baseQuery = fetchBaseQuery<{ foo?: string; bar?: number }>({ + prepareHeaders(headers, api) { + expectTypeOf(api.extraOptions).toEqualTypeOf<{ foo?: string; bar?: number }>() + prepare.call(undefined, arguments) + }, + }) + baseQuery('', commonBaseQueryApi, { foo: 'baz', bar: 5 }) + expect(prepare).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ extraOptions: { foo: 'baz', bar: 5 } }) + ) + + // ensure types + createApi({ + baseQuery, + endpoints(build) { + return { + testQuery: build.query({ + query: () => ({ url: '/echo', headers: {} }), + extraOptions: { + foo: 'asd', + bar: 1, + // @ts-expect-error + baz: 5, + }, + }), + testMutation: build.mutation({ + query: () => ({ + url: '/echo', + method: 'POST', + credentials: 'omit', + }), + extraOptions: { + foo: 'qwe', + bar: 15, + // @ts-expect-error + baz: 5, + }, + }), + } + }, + }) + }) }) test('can pass `headers` into `fetchBaseQuery`', async () => {