Skip to content

Commit ad63924

Browse files
Ensure covariant behavior: MockedResponses<X,Y> should be assignable to MockedResponse (#11848)
* Ensure covariant behavior: `MockedResponses<X,Y>` should be assignable to `MockedResponse` * api-explorer * Update .changeset/nasty-pens-dress.md Co-authored-by: Jerel Miller <[email protected]> --------- Co-authored-by: Jerel Miller <[email protected]>
1 parent d773000 commit ad63924

File tree

6 files changed

+71
-13
lines changed

6 files changed

+71
-13
lines changed

.api-reports/api-report-testing.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,11 @@ class Concast<T> extends Observable<T> {
440440
// @public (undocumented)
441441
type ConcastSourcesIterable<T> = Iterable<Source<T>>;
442442

443+
// @internal (undocumented)
444+
type CovariantUnaryFunction<out Arg, out Ret> = {
445+
fn(arg: Arg): Ret;
446+
}["fn"];
447+
443448
// Warning: (ae-forgotten-export) The symbol "ApolloClient" needs to be exported by the entry point index.d.ts
444449
// Warning: (ae-forgotten-export) The symbol "NormalizedCacheObject" needs to be exported by the entry point index.d.ts
445450
//
@@ -954,7 +959,7 @@ interface MockedProviderState {
954959
}
955960

956961
// @public (undocumented)
957-
export interface MockedResponse<TData = Record<string, any>, TVariables = Record<string, any>> {
962+
export interface MockedResponse<out TData = Record<string, any>, out TVariables = Record<string, any>> {
958963
// (undocumented)
959964
delay?: number;
960965
// (undocumented)
@@ -1552,8 +1557,10 @@ interface Resolvers {
15521557
};
15531558
}
15541559

1560+
// Warning: (ae-forgotten-export) The symbol "CovariantUnaryFunction" needs to be exported by the entry point index.d.ts
1561+
//
15551562
// @public (undocumented)
1556-
export type ResultFunction<T, V = Record<string, any>> = (variables: V) => T;
1563+
export type ResultFunction<T, V = Record<string, any>> = CovariantUnaryFunction<V, T>;
15571564

15581565
// @public (undocumented)
15591566
type SafeReadonly<T> = T extends object ? Readonly<T> : T;
@@ -1698,7 +1705,7 @@ interface UriFunction {
16981705
}
16991706

17001707
// @public (undocumented)
1701-
type VariableMatcher<V = Record<string, any>> = (variables: V) => boolean;
1708+
type VariableMatcher<V = Record<string, any>> = CovariantUnaryFunction<V, boolean>;
17021709

17031710
// @public (undocumented)
17041711
export function wait(ms: number): Promise<void>;

.api-reports/api-report-testing_core.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,11 @@ class Concast<T> extends Observable<T> {
439439
// @public (undocumented)
440440
type ConcastSourcesIterable<T> = Iterable<Source<T>>;
441441

442+
// @internal (undocumented)
443+
type CovariantUnaryFunction<out Arg, out Ret> = {
444+
fn(arg: Arg): Ret;
445+
}["fn"];
446+
442447
// Warning: (ae-forgotten-export) The symbol "ApolloClient" needs to be exported by the entry point index.d.ts
443448
// Warning: (ae-forgotten-export) The symbol "NormalizedCacheObject" needs to be exported by the entry point index.d.ts
444449
//
@@ -909,7 +914,7 @@ interface MockApolloLink extends ApolloLink {
909914
}
910915

911916
// @public (undocumented)
912-
export interface MockedResponse<TData = Record<string, any>, TVariables = Record<string, any>> {
917+
export interface MockedResponse<out TData = Record<string, any>, out TVariables = Record<string, any>> {
913918
// (undocumented)
914919
delay?: number;
915920
// (undocumented)
@@ -1509,8 +1514,10 @@ interface Resolvers {
15091514
};
15101515
}
15111516

1517+
// Warning: (ae-forgotten-export) The symbol "CovariantUnaryFunction" needs to be exported by the entry point index.d.ts
1518+
//
15121519
// @public (undocumented)
1513-
export type ResultFunction<T, V = Record<string, any>> = (variables: V) => T;
1520+
export type ResultFunction<T, V = Record<string, any>> = CovariantUnaryFunction<V, T>;
15141521

15151522
// @public (undocumented)
15161523
type SafeReadonly<T> = T extends object ? Readonly<T> : T;
@@ -1655,7 +1662,7 @@ interface UriFunction {
16551662
}
16561663

16571664
// @public (undocumented)
1658-
type VariableMatcher<V = Record<string, any>> = (variables: V) => boolean;
1665+
type VariableMatcher<V = Record<string, any>> = CovariantUnaryFunction<V, boolean>;
16591666

16601667
// @public (undocumented)
16611668
export function wait(ms: number): Promise<void>;

.changeset/nasty-pens-dress.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@apollo/client": patch
3+
---
4+
5+
Ensure covariant behavior: `MockedResponse<X,Y>` should be assignable to `MockedResponse`

.size-limits.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"dist/apollo-client.min.cjs": 39573,
2+
"dist/apollo-client.min.cjs": 39574,
33
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32821
44
}

src/testing/core/mocking/__tests__/mockLink.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,35 @@ test("removes fields with @client directives", async () => {
280280
await expect(stream.takeNext()).resolves.toEqual({ data: { a: 3, b: 4 } });
281281
}
282282
});
283+
284+
describe.skip("type tests", () => {
285+
const ANY = {} as any;
286+
test("covariant behaviour: `MockedResponses<X,Y>` should be assignable to `MockedResponse`", () => {
287+
let unspecificArray: MockedResponse[] = [];
288+
let specificArray: MockedResponse<{ foo: string }, { foo: string }>[] = [];
289+
let unspecificResponse: MockedResponse = ANY;
290+
let specificResponse: MockedResponse<{ foo: string }, { foo: string }> =
291+
ANY;
292+
293+
unspecificArray.push(specificResponse);
294+
unspecificArray.push(unspecificResponse);
295+
296+
specificArray.push(specificResponse);
297+
// @ts-expect-error
298+
specificArray.push(unspecificResponse);
299+
300+
unspecificArray = [specificResponse];
301+
unspecificArray = [unspecificResponse];
302+
unspecificArray = [specificResponse, unspecificResponse];
303+
304+
specificArray = [specificResponse];
305+
// @ts-expect-error
306+
specificArray = [unspecificResponse];
307+
// @ts-expect-error
308+
specificArray = [specificResponse, unspecificResponse];
309+
310+
unspecificResponse = specificResponse;
311+
// @ts-expect-error
312+
specificResponse = unspecificResponse;
313+
});
314+
});

src/testing/core/mocking/mockLink.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@ import {
2020
checkDocument,
2121
} from "../../../utilities/index.js";
2222

23-
export type ResultFunction<T, V = Record<string, any>> = (variables: V) => T;
23+
/** @internal */
24+
type CovariantUnaryFunction<out Arg, out Ret> = { fn(arg: Arg): Ret }["fn"];
2425

25-
export type VariableMatcher<V = Record<string, any>> = (
26-
variables: V
27-
) => boolean;
26+
export type ResultFunction<T, V = Record<string, any>> = CovariantUnaryFunction<
27+
V,
28+
T
29+
>;
30+
31+
export type VariableMatcher<V = Record<string, any>> = CovariantUnaryFunction<
32+
V,
33+
boolean
34+
>;
2835

2936
export interface MockedResponse<
30-
TData = Record<string, any>,
31-
TVariables = Record<string, any>,
37+
out TData = Record<string, any>,
38+
out TVariables = Record<string, any>,
3239
> {
3340
request: GraphQLRequest<TVariables>;
3441
maxUsageCount?: number;

0 commit comments

Comments
 (0)