Skip to content

Commit 51c0104

Browse files
EskiMojo14markerikson
authored andcommitted
add inference of raw result type from schema (or specifying from a third type parameter)
1 parent b85ff4f commit 51c0104

File tree

4 files changed

+92
-31
lines changed

4 files changed

+92
-31
lines changed

packages/toolkit/src/query/core/apiState.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ export type MutationKeys<Definitions extends EndpointDefinitions> = {
179179
}[keyof Definitions]
180180

181181
type BaseQuerySubState<
182-
D extends BaseEndpointDefinition<any, any, any>,
182+
D extends BaseEndpointDefinition<any, any, any, any>,
183183
DataType = ResultTypeFrom<D>,
184184
> = {
185185
/**
@@ -217,7 +217,7 @@ type BaseQuerySubState<
217217
}
218218

219219
export type QuerySubState<
220-
D extends BaseEndpointDefinition<any, any, any>,
220+
D extends BaseEndpointDefinition<any, any, any, any>,
221221
DataType = ResultTypeFrom<D>,
222222
> = Id<
223223
| ({ status: QueryStatus.fulfilled } & WithRequiredProp<
@@ -244,15 +244,17 @@ export type QuerySubState<
244244
export type InfiniteQueryDirection = 'forward' | 'backward'
245245

246246
export type InfiniteQuerySubState<
247-
D extends BaseEndpointDefinition<any, any, any>,
247+
D extends BaseEndpointDefinition<any, any, any, any>,
248248
> =
249249
D extends InfiniteQueryDefinition<any, any, any, any, any>
250250
? QuerySubState<D, InfiniteData<ResultTypeFrom<D>, PageParamFrom<D>>> & {
251251
direction?: InfiniteQueryDirection
252252
}
253253
: never
254254

255-
type BaseMutationSubState<D extends BaseEndpointDefinition<any, any, any>> = {
255+
type BaseMutationSubState<
256+
D extends BaseEndpointDefinition<any, any, any, any>,
257+
> = {
256258
requestId: string
257259
data?: ResultTypeFrom<D>
258260
error?:
@@ -265,8 +267,12 @@ type BaseMutationSubState<D extends BaseEndpointDefinition<any, any, any>> = {
265267
fulfilledTimeStamp?: number
266268
}
267269

268-
export type MutationSubState<D extends BaseEndpointDefinition<any, any, any>> =
269-
| (({ status: QueryStatus.fulfilled } & WithRequiredProp<
270+
export type MutationSubState<
271+
D extends BaseEndpointDefinition<any, any, any, any>,
272+
> =
273+
| (({
274+
status: QueryStatus.fulfilled
275+
} & WithRequiredProp<
270276
BaseMutationSubState<D>,
271277
'data' | 'fulfilledTimeStamp'
272278
>) & { error: undefined })

packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import type { ThunkDispatch, UnknownAction } from '@reduxjs/toolkit'
2-
import type { BaseQueryFn, BaseQueryMeta } from '../../baseQueryTypes'
2+
import type {
3+
BaseQueryFn,
4+
BaseQueryMeta,
5+
BaseQueryResult,
6+
} from '../../baseQueryTypes'
37
import type { BaseEndpointDefinition } from '../../endpointDefinitions'
48
import { DefinitionType, isAnyQueryDefinition } from '../../endpointDefinitions'
59
import type { QueryCacheKey, RootState } from '../apiState'
@@ -32,7 +36,8 @@ export interface QueryBaseLifecycleApi<
3236
{ type: DefinitionType.query } & BaseEndpointDefinition<
3337
QueryArg,
3438
BaseQuery,
35-
ResultType
39+
ResultType,
40+
BaseQueryResult<BaseQuery>
3641
>
3742
>
3843
/**
@@ -55,7 +60,8 @@ export type MutationBaseLifecycleApi<
5560
{ type: DefinitionType.mutation } & BaseEndpointDefinition<
5661
QueryArg,
5762
BaseQuery,
58-
ResultType
63+
ResultType,
64+
BaseQueryResult<BaseQuery>
5965
>
6066
>
6167
}

packages/toolkit/src/query/endpointDefinitions.ts

+55-20
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type EndpointDefinitionWithQuery<
4646
QueryArg,
4747
BaseQuery extends BaseQueryFn,
4848
ResultType,
49+
RawResultType extends BaseQueryResult<BaseQuery>,
4950
> = {
5051
/**
5152
* `query` can be a function that returns either a `string` or an `object` which is passed to your `baseQuery`. If you are using [fetchBaseQuery](./fetchBaseQuery), this can return either a `string` or an `object` of properties in `FetchArgs`. If you use your own custom [`baseQuery`](../../rtk-query/usage/customizing-queries), you can customize this behavior to your liking.
@@ -91,7 +92,7 @@ type EndpointDefinitionWithQuery<
9192
* A function to manipulate the data returned by a query or mutation.
9293
*/
9394
transformResponse?(
94-
baseQueryReturnValue: BaseQueryResult<BaseQuery>,
95+
baseQueryReturnValue: RawResultType,
9596
meta: BaseQueryMeta<BaseQuery>,
9697
arg: QueryArg,
9798
): ResultType | Promise<ResultType>
@@ -105,7 +106,7 @@ type EndpointDefinitionWithQuery<
105106
): unknown
106107

107108
/** A schema for the result *before* it's passed to `transformResponse` */
108-
rawResponseSchema?: StandardSchemaV1<BaseQueryResult<BaseQuery>>
109+
rawResponseSchema?: StandardSchemaV1<RawResultType>
109110

110111
/** A schema for the error object returned by the `query` or `queryFn`, *before* it's passed to `transformErrorResponse` */
111112
rawErrorResponseSchema?: StandardSchemaV1<BaseQueryError<BaseQuery>>
@@ -183,10 +184,16 @@ export type BaseEndpointDefinition<
183184
QueryArg,
184185
BaseQuery extends BaseQueryFn,
185186
ResultType,
187+
RawResultType extends BaseQueryResult<BaseQuery> = BaseQueryResult<BaseQuery>,
186188
> = (
187189
| ([CastAny<BaseQueryResult<BaseQuery>, {}>] extends [NEVER]
188190
? never
189-
: EndpointDefinitionWithQuery<QueryArg, BaseQuery, ResultType>)
191+
: EndpointDefinitionWithQuery<
192+
QueryArg,
193+
BaseQuery,
194+
ResultType,
195+
RawResultType
196+
>)
190197
| EndpointDefinitionWithQueryFn<QueryArg, BaseQuery, ResultType>
191198
) & {
192199
/** A schema for the arguments to be passed to the `query` or `queryFn` */
@@ -550,7 +557,8 @@ export type QueryDefinition<
550557
TagTypes extends string,
551558
ResultType,
552559
ReducerPath extends string = string,
553-
> = BaseEndpointDefinition<QueryArg, BaseQuery, ResultType> &
560+
RawResultType extends BaseQueryResult<BaseQuery> = BaseQueryResult<BaseQuery>,
561+
> = BaseEndpointDefinition<QueryArg, BaseQuery, ResultType, RawResultType> &
554562
QueryExtraOptions<TagTypes, ResultType, QueryArg, BaseQuery, ReducerPath>
555563

556564
export type InfiniteQueryTypes<
@@ -743,12 +751,14 @@ export type InfiniteQueryDefinition<
743751
TagTypes extends string,
744752
ResultType,
745753
ReducerPath extends string = string,
754+
RawResultType extends BaseQueryResult<BaseQuery> = BaseQueryResult<BaseQuery>,
746755
> =
747756
// Infinite query endpoints receive `{queryArg, pageParam}`
748757
BaseEndpointDefinition<
749758
InfiniteQueryCombinedArg<QueryArg, PageParam>,
750759
BaseQuery,
751-
ResultType
760+
ResultType,
761+
RawResultType
752762
> &
753763
InfiniteQueryExtraOptions<
754764
TagTypes,
@@ -876,7 +886,8 @@ export type MutationDefinition<
876886
TagTypes extends string,
877887
ResultType,
878888
ReducerPath extends string = string,
879-
> = BaseEndpointDefinition<QueryArg, BaseQuery, ResultType> &
889+
RawResultType extends BaseQueryResult<BaseQuery> = BaseQueryResult<BaseQuery>,
890+
> = BaseEndpointDefinition<QueryArg, BaseQuery, ResultType, RawResultType> &
880891
MutationExtraOptions<TagTypes, ResultType, QueryArg, BaseQuery, ReducerPath>
881892

882893
export type EndpointDefinition<
@@ -960,9 +971,21 @@ export type EndpointBuilder<
960971
*});
961972
*```
962973
*/
963-
query<ResultType, QueryArg>(
974+
query<
975+
ResultType,
976+
QueryArg,
977+
RawResultType extends
978+
BaseQueryResult<BaseQuery> = BaseQueryResult<BaseQuery>,
979+
>(
964980
definition: OmitFromUnion<
965-
QueryDefinition<QueryArg, BaseQuery, TagTypes, ResultType, ReducerPath>,
981+
QueryDefinition<
982+
QueryArg,
983+
BaseQuery,
984+
TagTypes,
985+
ResultType,
986+
ReducerPath,
987+
RawResultType
988+
>,
966989
'type'
967990
>,
968991
): QueryDefinition<QueryArg, BaseQuery, TagTypes, ResultType, ReducerPath>
@@ -992,14 +1015,20 @@ export type EndpointBuilder<
9921015
* });
9931016
* ```
9941017
*/
995-
mutation<ResultType, QueryArg>(
1018+
mutation<
1019+
ResultType,
1020+
QueryArg,
1021+
RawResultType extends
1022+
BaseQueryResult<BaseQuery> = BaseQueryResult<BaseQuery>,
1023+
>(
9961024
definition: OmitFromUnion<
9971025
MutationDefinition<
9981026
QueryArg,
9991027
BaseQuery,
10001028
TagTypes,
10011029
ResultType,
1002-
ReducerPath
1030+
ReducerPath,
1031+
RawResultType
10031032
>,
10041033
'type'
10051034
>,
@@ -1066,27 +1095,31 @@ export function expandTagDescription(
10661095
return typeof description === 'string' ? { type: description } : description
10671096
}
10681097

1069-
export type QueryArgFrom<D extends BaseEndpointDefinition<any, any, any>> =
1070-
D extends BaseEndpointDefinition<infer QA, any, any> ? QA : never
1098+
export type QueryArgFrom<D extends BaseEndpointDefinition<any, any, any, any>> =
1099+
D extends BaseEndpointDefinition<infer QA, any, any, any> ? QA : never
10711100

10721101
// Just extracting `QueryArg` from `BaseEndpointDefinition`
10731102
// doesn't sufficiently match here.
10741103
// We need to explicitly match against `InfiniteQueryDefinition`
10751104
export type InfiniteQueryArgFrom<
1076-
D extends BaseEndpointDefinition<any, any, any>,
1077-
> = D extends InfiniteQueryDefinition<infer QA, any, any, any, any> ? QA : never
1105+
D extends BaseEndpointDefinition<any, any, any, any>,
1106+
> =
1107+
D extends InfiniteQueryDefinition<infer QA, any, any, any, any, any>
1108+
? QA
1109+
: never
10781110

10791111
export type QueryArgFromAnyQuery<
1080-
D extends BaseEndpointDefinition<any, any, any>,
1112+
D extends BaseEndpointDefinition<any, any, any, any>,
10811113
> =
1082-
D extends InfiniteQueryDefinition<any, any, any, any, any>
1114+
D extends InfiniteQueryDefinition<any, any, any, any, any, any>
10831115
? InfiniteQueryArgFrom<D>
10841116
: D extends QueryDefinition<any, any, any, any>
10851117
? QueryArgFrom<D>
10861118
: never
10871119

1088-
export type ResultTypeFrom<D extends BaseEndpointDefinition<any, any, any>> =
1089-
D extends BaseEndpointDefinition<any, any, infer RT> ? RT : unknown
1120+
export type ResultTypeFrom<
1121+
D extends BaseEndpointDefinition<any, any, any, any>,
1122+
> = D extends BaseEndpointDefinition<any, any, infer RT, any> ? RT : unknown
10901123

10911124
export type ReducerPathFrom<
10921125
D extends EndpointDefinition<any, any, any, any, any>,
@@ -1096,9 +1129,11 @@ export type TagTypesFrom<D extends EndpointDefinition<any, any, any, any>> =
10961129
D extends EndpointDefinition<any, any, infer RP, any> ? RP : unknown
10971130

10981131
export type PageParamFrom<
1099-
D extends InfiniteQueryDefinition<any, any, any, any, any>,
1132+
D extends InfiniteQueryDefinition<any, any, any, any, any, any>,
11001133
> =
1101-
D extends InfiniteQueryDefinition<any, infer PP, any, any, any> ? PP : unknown
1134+
D extends InfiniteQueryDefinition<any, infer PP, any, any, any, any>
1135+
? PP
1136+
: unknown
11021137

11031138
export type InfiniteQueryCombinedArg<QueryArg, PageParam> = {
11041139
queryArg: QueryArg

packages/toolkit/src/query/tests/createApi.test-d.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { setupApiStore } from '@internal/tests/utils/helpers'
2-
import type { SerializedError } from '@reduxjs/toolkit'
3-
import { configureStore } from '@reduxjs/toolkit'
2+
import type { EntityState, SerializedError } from '@reduxjs/toolkit'
3+
import { configureStore, createEntityAdapter } from '@reduxjs/toolkit'
44
import type {
55
DefinitionsFromApi,
66
FetchBaseQueryError,
@@ -467,6 +467,7 @@ describe('type tests', () => {
467467
})
468468
})
469469
test('schemas as a source of inference', () => {
470+
const postAdapter = createEntityAdapter<Post>()
470471
const api = createApi({
471472
baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }),
472473
endpoints: (build) => ({
@@ -482,6 +483,14 @@ describe('type tests', () => {
482483
argSchema,
483484
responseSchema: postSchema,
484485
}),
486+
query3: build.query({
487+
query: (_arg: void) => `/posts`,
488+
rawResponseSchema: v.array(postSchema),
489+
transformResponse: (posts) => {
490+
expectTypeOf(posts).toEqualTypeOf<Post[]>()
491+
return postAdapter.getInitialState(undefined, posts)
492+
},
493+
}),
485494
}),
486495
})
487496

@@ -496,6 +505,11 @@ describe('type tests', () => {
496505
expectTypeOf(
497506
api.endpoints.query2.Types.ResultType,
498507
).toEqualTypeOf<Post>()
508+
509+
expectTypeOf(api.endpoints.query3.Types.QueryArg).toEqualTypeOf<void>()
510+
expectTypeOf(api.endpoints.query3.Types.ResultType).toEqualTypeOf<
511+
EntityState<Post, Post['id']>
512+
>()
499513
})
500514
})
501515
})

0 commit comments

Comments
 (0)