Skip to content

Commit 3601246

Browse files
authoredJan 14, 2025··
Handle tagged/branded primitive types when used with Unmasked (#12270)
1 parent d57429d commit 3601246

18 files changed

+62
-19
lines changed
 

‎.api-reports/api-report-cache.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
11201120
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
11211121

11221122
// @public (undocumented)
1123-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
1123+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
11241124
" $fragmentRefs"?: infer FragmentRefs;
11251125
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
11261126
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-core.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2417,7 +2417,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
24172417
export type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
24182418

24192419
// @public (undocumented)
2420-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
2420+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
24212421
" $fragmentRefs"?: infer FragmentRefs;
24222422
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
24232423
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
619619
export type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
620620

621621
// @public (undocumented)
622-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
622+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
623623
" $fragmentRefs"?: infer FragmentRefs;
624624
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
625625
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-react.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2213,7 +2213,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
22132213
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
22142214

22152215
// @public (undocumented)
2216-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
2216+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
22172217
" $fragmentRefs"?: infer FragmentRefs;
22182218
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
22192219
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-react_components.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1946,7 +1946,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
19461946
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
19471947

19481948
// @public (undocumented)
1949-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
1949+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
19501950
" $fragmentRefs"?: infer FragmentRefs;
19511951
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
19521952
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-react_context.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1866,7 +1866,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
18661866
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
18671867

18681868
// @public (undocumented)
1869-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
1869+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
18701870
" $fragmentRefs"?: infer FragmentRefs;
18711871
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
18721872
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-react_hoc.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
18701870
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
18711871

18721872
// @public (undocumented)
1873-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
1873+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
18741874
" $fragmentRefs"?: infer FragmentRefs;
18751875
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
18761876
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-react_hooks.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2036,7 +2036,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
20362036
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
20372037

20382038
// @public (undocumented)
2039-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
2039+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
20402040
" $fragmentRefs"?: infer FragmentRefs;
20412041
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
20422042
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-react_internal.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2088,7 +2088,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
20882088
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
20892089

20902090
// @public (undocumented)
2091-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
2091+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
20922092
" $fragmentRefs"?: infer FragmentRefs;
20932093
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
20942094
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-react_ssr.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1851,7 +1851,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
18511851
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
18521852

18531853
// @public (undocumented)
1854-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
1854+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
18551855
" $fragmentRefs"?: infer FragmentRefs;
18561856
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
18571857
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1902,7 +1902,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
19021902
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
19031903

19041904
// @public (undocumented)
1905-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
1905+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
19061906
" $fragmentRefs"?: infer FragmentRefs;
19071907
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
19081908
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1859,7 +1859,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
18591859
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
18601860

18611861
// @public (undocumented)
1862-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
1862+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
18631863
" $fragmentRefs"?: infer FragmentRefs;
18641864
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
18651865
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.api-reports/api-report-utilities.api.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -729,8 +729,6 @@ type DeepOmitArray<T extends any[], K> = {
729729
[P in keyof T]: DeepOmit<T[P], K>;
730730
};
731731

732-
// Warning: (ae-forgotten-export) The symbol "Primitive" needs to be exported by the entry point index.d.ts
733-
//
734732
// @public (undocumented)
735733
type DeepOmitPrimitive = Primitive | Function;
736734

@@ -2142,7 +2140,7 @@ export type Prettify<T> = {
21422140
export function preventUnhandledRejection<T>(promise: Promise<T>): Promise<T>;
21432141

21442142
// @public (undocumented)
2145-
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
2143+
export type Primitive = null | undefined | string | number | boolean | symbol | bigint;
21462144

21472145
// @public (undocumented)
21482146
const print_2: ((ast: ASTNode) => string) & {
@@ -2780,7 +2778,7 @@ type UnionToIntersection_2<U> = (U extends any ? (k: U) => void : never) extends
27802778
type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
27812779

27822780
// @public (undocumented)
2783-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
2781+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
27842782
" $fragmentRefs"?: infer FragmentRefs;
27852783
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
27862784
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -2882,7 +2882,7 @@ type unionToIntersection<T> = (T extends unknown ? (x: T) => unknown : never) ex
28822882
export type Unmasked<TData> = true extends IsAny<TData> ? TData : TData extends object ? true extends ContainsFragmentsRefs<TData> ? UnwrapFragmentRefs<RemoveMaskedMarker<RemoveFragmentName<TData>>> : TData : TData;
28832883

28842884
// @public (undocumented)
2885-
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
2885+
type UnwrapFragmentRefs<TData> = true extends IsAny<TData> ? TData : TData extends any ? TData extends Primitive ? TData : string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends {
28862886
" $fragmentRefs"?: infer FragmentRefs;
28872887
} ? UnwrapFragmentRefs<CombineIntersection<Omit<TData, " $fragmentRefs"> | RemoveFragmentName<NonNullable<NonNullable<FragmentRefs>[keyof NonNullable<FragmentRefs>]>>>> : TData extends object ? {
28882888
[K in keyof TData]: UnwrapFragmentRefs<TData[K]>;

‎.changeset/tiny-ants-bow.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@apollo/client": patch
3+
---
4+
5+
Fix handling of tagged/branded primitive types when used as scalar values with `Unmasked`.

‎src/masking/__benches__/types.bench.ts

+33
Original file line numberDiff line numberDiff line change
@@ -627,3 +627,36 @@ test("MaybeMasked can be called with a generic if `mode` is not set to `unmask`"
627627
withGenericResult({} as any);
628628
withGenericDocument({} as any);
629629
});
630+
631+
test("Unmasked handles branded primitive types", (prefix) => {
632+
type Branded<T, Name extends string> = T & { __branded?: Name };
633+
type UUID = Branded<string, "UUID">;
634+
type Source = {
635+
__typename: "Foo";
636+
id: UUID;
637+
name: string;
638+
} & { " $fragmentName"?: "UserFieldsFragment" } & {
639+
" $fragmentRefs"?: {
640+
FooFragment: FooFragment;
641+
};
642+
};
643+
type FooFragment = {
644+
__typename: "Foo";
645+
age: number;
646+
} & { " $fragmentName"?: "UserFieldsFragment" };
647+
648+
bench(prefix + "instantiations", () => {
649+
return {} as Unmasked<Source>;
650+
}).types([5, "instantiations"]);
651+
652+
bench(prefix + "functionality", () => {
653+
const x = {} as Unmasked<Source>;
654+
655+
expectTypeOf(x).branded.toEqualTypeOf<{
656+
__typename: "Foo";
657+
id: UUID;
658+
name: string;
659+
age: number;
660+
}>();
661+
});
662+
});

‎src/masking/internal/types.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import type { Prettify, RemoveIndexSignature } from "../../utilities/index.js";
1+
import type {
2+
Prettify,
3+
Primitive,
4+
RemoveIndexSignature,
5+
} from "../../utilities/index.js";
26

37
export type IsAny<T> = 0 extends 1 & T ? true : false;
48

59
export type UnwrapFragmentRefs<TData> =
610
true extends IsAny<TData> ? TData
711
: TData extends any ?
8-
// Leave TData alone if it is Record<string, any> and not a specific shape
12+
// Ensure tagged/branded types are left alone (i.e. type UUID = string & { ... })
13+
TData extends Primitive ? TData
14+
: // Leave TData alone if it is Record<string, any> and not a specific shape
915
string extends keyof TData ? TData
1016
: // short-circuit on empty object
1117
keyof TData extends never ? TData

‎src/utilities/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ export type { DeepOmit } from "./types/DeepOmit.js";
137137
export type { DeepPartial } from "./types/DeepPartial.js";
138138
export type { OnlyRequiredProperties } from "./types/OnlyRequiredProperties.js";
139139
export type { Prettify } from "./types/Prettify.js";
140+
export type { Primitive } from "./types/Primitive.js";
140141
export type { UnionToIntersection } from "./types/UnionToIntersection.js";
141142
export type { NoInfer } from "./types/NoInfer.js";
142143
export type { RemoveIndexSignature } from "./types/RemoveIndexSignature.js";

0 commit comments

Comments
 (0)
Please sign in to comment.