Skip to content

Commit 8962cef

Browse files
authoredApr 16, 2023
Merge pull request #2953 from dmitrigrabov/use-transformed-response-result-type
Fix #1441
2 parents 53df220 + cb611a0 commit 8962cef

File tree

4 files changed

+147
-10
lines changed

4 files changed

+147
-10
lines changed
 

‎packages/toolkit/src/query/apiTypes.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {
22
EndpointDefinitions,
33
EndpointBuilder,
44
EndpointDefinition,
5-
ReplaceTagTypes,
5+
UpdateDefinitions,
66
} from './endpointDefinitions'
77
import type {
88
UnionToIntersection,
@@ -93,11 +93,15 @@ export type Api<
9393
/**
9494
*A function to enhance a generated API with additional information. Useful with code-generation.
9595
*/
96-
enhanceEndpoints<NewTagTypes extends string = never>(_: {
96+
enhanceEndpoints<
97+
NewTagTypes extends string = never,
98+
NewDefinitions extends EndpointDefinitions = never
99+
>(_: {
97100
addTagTypes?: readonly NewTagTypes[]
98-
endpoints?: ReplaceTagTypes<
101+
endpoints?: UpdateDefinitions<
99102
Definitions,
100-
TagTypes | NoInfer<NewTagTypes>
103+
TagTypes | NoInfer<NewTagTypes>,
104+
NewDefinitions
101105
> extends infer NewDefinitions
102106
? {
103107
[K in keyof NewDefinitions]?:
@@ -107,7 +111,7 @@ export type Api<
107111
: never
108112
}): Api<
109113
BaseQuery,
110-
ReplaceTagTypes<Definitions, TagTypes | NewTagTypes>,
114+
UpdateDefinitions<Definitions, TagTypes | NewTagTypes, NewDefinitions>,
111115
ReducerPath,
112116
TagTypes | NewTagTypes,
113117
Enhancers

‎packages/toolkit/src/query/endpointDefinitions.ts

+61-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import type {
1616
MaybePromise,
1717
OmitFromUnion,
1818
CastAny,
19+
NonUndefined,
1920
} from './tsHelpers'
2021
import type { NEVER } from './fakeBaseQuery'
22+
import type { Api } from '@reduxjs/toolkit/query'
2123

2224
const resultType = /* @__PURE__ */ Symbol()
2325
const baseQuery = /* @__PURE__ */ Symbol()
@@ -775,9 +777,58 @@ export type ReducerPathFrom<
775777
export type TagTypesFrom<D extends EndpointDefinition<any, any, any, any>> =
776778
D extends EndpointDefinition<any, any, infer RP, any> ? RP : unknown
777779

778-
export type ReplaceTagTypes<
780+
export type TagTypesFromApi<T> = T extends Api<any, any, any, infer TagTypes>
781+
? TagTypes
782+
: never
783+
784+
export type DefinitionsFromApi<T> = T extends Api<
785+
any,
786+
infer Definitions,
787+
any,
788+
any
789+
>
790+
? Definitions
791+
: never
792+
793+
export type TransformedResponse<
794+
NewDefinitions extends EndpointDefinitions,
795+
K,
796+
ResultType
797+
> = K extends keyof NewDefinitions
798+
? NewDefinitions[K]['transformResponse'] extends undefined
799+
? ResultType
800+
: ReturnType<NonUndefined<NewDefinitions[K]['transformResponse']>>
801+
: ResultType
802+
803+
export type OverrideResultType<Definition, NewResultType> =
804+
Definition extends QueryDefinition<
805+
infer QueryArg,
806+
infer BaseQuery,
807+
infer TagTypes,
808+
any,
809+
infer ReducerPath
810+
>
811+
? QueryDefinition<QueryArg, BaseQuery, TagTypes, NewResultType, ReducerPath>
812+
: Definition extends MutationDefinition<
813+
infer QueryArg,
814+
infer BaseQuery,
815+
infer TagTypes,
816+
any,
817+
infer ReducerPath
818+
>
819+
? MutationDefinition<
820+
QueryArg,
821+
BaseQuery,
822+
TagTypes,
823+
NewResultType,
824+
ReducerPath
825+
>
826+
: never
827+
828+
export type UpdateDefinitions<
779829
Definitions extends EndpointDefinitions,
780-
NewTagTypes extends string
830+
NewTagTypes extends string,
831+
NewDefinitions extends EndpointDefinitions
781832
> = {
782833
[K in keyof Definitions]: Definitions[K] extends QueryDefinition<
783834
infer QueryArg,
@@ -786,7 +837,13 @@ export type ReplaceTagTypes<
786837
infer ResultType,
787838
infer ReducerPath
788839
>
789-
? QueryDefinition<QueryArg, BaseQuery, NewTagTypes, ResultType, ReducerPath>
840+
? QueryDefinition<
841+
QueryArg,
842+
BaseQuery,
843+
NewTagTypes,
844+
TransformedResponse<NewDefinitions, K, ResultType>,
845+
ReducerPath
846+
>
790847
: Definitions[K] extends MutationDefinition<
791848
infer QueryArg,
792849
infer BaseQuery,
@@ -798,7 +855,7 @@ export type ReplaceTagTypes<
798855
QueryArg,
799856
BaseQuery,
800857
NewTagTypes,
801-
ResultType,
858+
TransformedResponse<NewDefinitions, K, ResultType>,
802859
ReducerPath
803860
>
804861
: never

‎packages/toolkit/src/query/tests/createApi.test.ts

+75-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { configureStore, createAction, createReducer } from '@reduxjs/toolkit'
2+
import type { SerializedError } from '@reduxjs/toolkit'
23
import type {
34
Api,
45
MutationDefinition,
56
QueryDefinition,
67
} from '@reduxjs/toolkit/query'
78
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
8-
import type { FetchBaseQueryMeta } from '@reduxjs/toolkit/dist/query/fetchBaseQuery'
9+
import type {
10+
FetchBaseQueryError,
11+
FetchBaseQueryMeta,
12+
} from '@reduxjs/toolkit/dist/query/fetchBaseQuery'
913

1014
import {
1115
ANY,
@@ -19,6 +23,11 @@ import { server } from './mocks/server'
1923
import { rest } from 'msw'
2024
import type { SerializeQueryArgs } from '../defaultSerializeQueryArgs'
2125
import { string } from 'yargs'
26+
import type {
27+
DefinitionsFromApi,
28+
OverrideResultType,
29+
TagTypesFromApi,
30+
} from '@reduxjs/toolkit/dist/query/endpointDefinitions'
2231

2332
const originalEnv = process.env.NODE_ENV
2433
beforeAll(() => void ((process.env as any).NODE_ENV = 'development'))
@@ -522,6 +531,71 @@ describe('endpoint definition typings', () => {
522531
['modified2', { ...commonBaseQueryApi, forced: undefined }, undefined],
523532
])
524533
})
534+
535+
test('updated transform response types', async () => {
536+
const baseApi = createApi({
537+
baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }),
538+
tagTypes: ['old'],
539+
endpoints: (build) => ({
540+
query1: build.query<'out1', void>({ query: () => 'success' }),
541+
mutation1: build.mutation<'out1', void>({ query: () => 'success' }),
542+
}),
543+
})
544+
545+
type Transformed = { value: string }
546+
547+
type Definitions = DefinitionsFromApi<typeof api>
548+
type TagTypes = TagTypesFromApi<typeof api>
549+
550+
type Q1Definition = OverrideResultType<Definitions['query1'], Transformed>
551+
type M1Definition = OverrideResultType<
552+
Definitions['mutation1'],
553+
Transformed
554+
>
555+
556+
type UpdatedDefitions = Omit<Definitions, 'query1' | 'mutation1'> & {
557+
query1: Q1Definition
558+
mutation1: M1Definition
559+
}
560+
561+
const enhancedApi = baseApi.enhanceEndpoints<TagTypes, UpdatedDefitions>({
562+
endpoints: {
563+
query1: {
564+
transformResponse: (a, b, c) => ({
565+
value: 'transformed',
566+
}),
567+
},
568+
mutation1: {
569+
transformResponse: (a, b, c) => ({
570+
value: 'transformed',
571+
}),
572+
},
573+
},
574+
})
575+
576+
const storeRef = setupApiStore(enhancedApi, undefined, {
577+
withoutTestLifecycles: true,
578+
})
579+
580+
const queryResponse = await storeRef.store.dispatch(
581+
enhancedApi.endpoints.query1.initiate()
582+
)
583+
expect(queryResponse.data).toEqual({ value: 'transformed' })
584+
expectType<Transformed | Promise<Transformed> | undefined>(
585+
queryResponse.data
586+
)
587+
588+
const mutationResponse = await storeRef.store.dispatch(
589+
enhancedApi.endpoints.mutation1.initiate()
590+
)
591+
expectType<
592+
| { data: Transformed | Promise<Transformed> }
593+
| { error: FetchBaseQueryError | SerializedError }
594+
>(mutationResponse)
595+
expect('data' in mutationResponse && mutationResponse.data).toEqual({
596+
value: 'transformed',
597+
})
598+
})
525599
})
526600
})
527601

‎packages/toolkit/src/query/tsHelpers.ts

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export type OptionalIfAllPropsOptional<T> = HasRequiredProps<T, T, T | never>
3232

3333
export type NoInfer<T> = [T][T extends any ? 0 : never]
3434

35+
export type NonUndefined<T> = T extends undefined ? never : T
36+
3537
export type UnwrapPromise<T> = T extends PromiseLike<infer V> ? V : T
3638

3739
export type MaybePromise<T> = T | PromiseLike<T>

0 commit comments

Comments
 (0)
Please sign in to comment.