Skip to content

Commit bfcd16e

Browse files
authored
Allow FragmentType to be called as FragmentType<TypedDocumentNode> (#13009)
* Allow `FragmentType` not only to be called as `FragmentType<TData>`, but also as `FragmentType<TypedDocumentNode>`. * update non-type-import * simplify type * chores * fixup 🤦 * lint * Clean up Prettier, Size-limit, and Api-Extractor --------- Co-authored-by: phryneas <[email protected]>
1 parent 00e9054 commit bfcd16e

File tree

6 files changed

+76
-14
lines changed

6 files changed

+76
-14
lines changed

.api-reports/api-report-masking.api.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import type { ApolloCache } from '@apollo/client';
88
import type { ApplyHKTImplementationWithDefault } from '@apollo/client/utilities/internal';
99
import type { DocumentNode } from '@apollo/client';
10+
import type { DocumentTypeDecoration } from '@graphql-typed-document-node/core';
1011
import type { HKT } from '@apollo/client/utilities';
1112
import type { IsAny } from '@apollo/client/utilities/internal';
1213
import type { Prettify } from '@apollo/client/utilities/internal';
@@ -63,7 +64,7 @@ type ExtractByMatchingTypeNames<Union extends {
6364
// Warning: (ae-forgotten-export) The symbol "PreserveTypes" needs to be exported by the entry point index.d.ts
6465
//
6566
// @public
66-
export type FragmentType<TFragmentData> = ApplyHKTImplementationWithDefault<TypeOverrides, "FragmentType", PreserveTypes.TypeOverrides, TFragmentData>;
67+
export type FragmentType<TFragmentDataOrTypedDocumentNode> = ApplyHKTImplementationWithDefault<TypeOverrides, "FragmentType", PreserveTypes.TypeOverrides, TFragmentDataOrTypedDocumentNode extends (DocumentTypeDecoration<infer TFragmentData, any>) ? TFragmentData : TFragmentDataOrTypedDocumentNode>;
6768

6869
// @public (undocumented)
6970
export namespace GraphQLCodegenDataMasking {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { ASTNode } from 'graphql';
88
import { disableExperimentalFragmentVariables } from 'graphql-tag';
99
import { disableFragmentWarnings } from 'graphql-tag';
1010
import { DocumentNode } from 'graphql';
11+
import type { DocumentTypeDecoration } from '@graphql-typed-document-node/core';
1112
import { enableExperimentalFragmentVariables } from 'graphql-tag';
1213
import type { FieldNode } from 'graphql';
1314
import type { FormattedExecutionResult } from 'graphql';
@@ -1216,7 +1217,7 @@ interface FragmentRegistryAPI {
12161217
// Warning: (ae-forgotten-export) The symbol "PreserveTypes" needs to be exported by the entry point index.d.ts
12171218
//
12181219
// @public
1219-
export type FragmentType<TFragmentData> = ApplyHKTImplementationWithDefault<TypeOverrides, "FragmentType", PreserveTypes.TypeOverrides, TFragmentData>;
1220+
export type FragmentType<TFragmentDataOrTypedDocumentNode> = ApplyHKTImplementationWithDefault<TypeOverrides, "FragmentType", PreserveTypes.TypeOverrides, TFragmentDataOrTypedDocumentNode extends (DocumentTypeDecoration<infer TFragmentData, any>) ? TFragmentData : TFragmentDataOrTypedDocumentNode>;
12201221

12211222
// @public @deprecated (undocumented)
12221223
export const from: typeof ApolloLink.from;

.changeset/few-parrots-raise.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+
Allow `FragmentType` not only to be called as `FragmentType<TData>`, but also as `FragmentType<TypedDocumentNode>`.

.size-limits.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 45497,
3-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 40156,
4-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 34540,
5-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 28414
2+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 45545,
3+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 40136,
4+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 34567,
5+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 28389
66
}

src/masking/__benches__/types.bench.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import { setup } from "@ark/attest";
33
import { expectTypeOf } from "expect-type";
44

55
import type { TypedDocumentNode } from "@apollo/client";
6-
import type { MaybeMasked, Unmasked } from "@apollo/client/masking";
6+
import type {
7+
FragmentType,
8+
MaybeMasked,
9+
Unmasked,
10+
} from "@apollo/client/masking";
711
import type { DeepPartial } from "@apollo/client/utilities";
812

913
import type { ContainsFragmentsRefs } from "../internal/types.js";
@@ -267,7 +271,7 @@ test("Unmasked handles odd types", (prefix) => {
267271

268272
bench(prefix + "unknown instantiations", () => {
269273
attest<unknown, Unmasked<unknown>>();
270-
}).types([48, "instantiations"]);
274+
}).types([46, "instantiations"]);
271275

272276
bench(prefix + "unknown functionality", () => {
273277
expectTypeOf<Unmasked<unknown>>().toBeUnknown();
@@ -661,3 +665,47 @@ test("Unmasked handles branded primitive types", (prefix) => {
661665
}>();
662666
});
663667
});
668+
669+
test("FragmentType", () => {
670+
type UserFieldsFragment = {
671+
__typename: "User";
672+
id: number;
673+
age: number;
674+
} & { " $fragmentName"?: "UserFieldsFragment" } & {
675+
" $fragmentRefs"?: {
676+
NameFieldsFragment: NameFieldsFragment;
677+
};
678+
};
679+
680+
type NameFieldsFragment = {
681+
__typename: "User";
682+
firstName: string;
683+
lastName: string;
684+
} & { " $fragmentName"?: "NameFieldsFragment" };
685+
686+
type Source = UserFieldsFragment;
687+
688+
const USER_FIELDS_FRAGMENT: TypedDocumentNode<UserFieldsFragment> = {} as any;
689+
690+
bench("normal usage", () => {
691+
expectTypeOf<FragmentType<Source>>().toEqualTypeOf<{
692+
" $fragmentRefs"?: {
693+
UserFieldsFragment: UserFieldsFragment;
694+
};
695+
}>();
696+
});
697+
698+
bench("passing in the type of a `TypedDocumentNode`", () => {
699+
expectTypeOf<FragmentType<typeof USER_FIELDS_FRAGMENT>>().toEqualTypeOf<{
700+
" $fragmentRefs"?: {
701+
UserFieldsFragment: UserFieldsFragment;
702+
};
703+
}>();
704+
});
705+
706+
bench("both usages yield the same result", () => {
707+
expectTypeOf<FragmentType<Source>>().toEqualTypeOf<
708+
FragmentType<typeof USER_FIELDS_FRAGMENT>
709+
>();
710+
});
711+
});

src/masking/types.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { DocumentTypeDecoration } from "@graphql-typed-document-node/core";
2+
13
import type { TypeOverrides } from "@apollo/client";
24
import type { ApplyHKTImplementationWithDefault } from "@apollo/client/utilities/internal";
35

@@ -6,12 +8,17 @@ import type { PreserveTypes } from "./PreserveTypes.js";
68
/**
79
* Type used with [fragments](https://apollographql.com/docs/react/data/fragments#using-with-fragments) to ensure parent objects contain the fragment spread from the type.
810
*/
9-
export type FragmentType<TFragmentData> = ApplyHKTImplementationWithDefault<
10-
TypeOverrides,
11-
"FragmentType",
12-
PreserveTypes.TypeOverrides,
13-
TFragmentData
14-
>;
11+
export type FragmentType<TFragmentDataOrTypedDocumentNode> =
12+
ApplyHKTImplementationWithDefault<
13+
TypeOverrides,
14+
"FragmentType",
15+
PreserveTypes.TypeOverrides,
16+
TFragmentDataOrTypedDocumentNode extends (
17+
DocumentTypeDecoration<infer TFragmentData, any>
18+
) ?
19+
TFragmentData
20+
: TFragmentDataOrTypedDocumentNode
21+
>;
1522

1623
/** Unwraps `TData` into its unmasked type. */
1724
export type Unmasked<TData> = ApplyHKTImplementationWithDefault<

0 commit comments

Comments
 (0)