From 851deb06f42eb255b4839c2b88430f991943ae0f Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 12 Dec 2024 06:03:02 -0700 Subject: [PATCH] Ensure `MaybeMasked` doesn't unwrap if it contains `any` (#12204) Co-authored-by: Lenz Weber-Tronic Co-authored-by: phryneas --- .api-reports/api-report-cache.api.md | 13 +- .api-reports/api-report-core.api.md | 13 +- .api-reports/api-report-masking.api.md | 13 +- .api-reports/api-report-react.api.md | 13 +- .../api-report-react_components.api.md | 13 +- .api-reports/api-report-react_context.api.md | 13 +- .api-reports/api-report-react_hoc.api.md | 13 +- .api-reports/api-report-react_hooks.api.md | 13 +- .api-reports/api-report-react_internal.api.md | 13 +- .api-reports/api-report-react_ssr.api.md | 13 +- .api-reports/api-report-testing.api.md | 13 +- .api-reports/api-report-testing_core.api.md | 13 +- .api-reports/api-report-utilities.api.md | 12 +- .api-reports/api-report.api.md | 13 +- .changeset/friendly-papayas-breathe.md | 5 + .changeset/happy-weeks-buy.md | 5 + .changeset/three-pandas-smash.md | 5 + src/masking/__benches__/types.bench.ts | 115 +++++++++++++++++- src/masking/internal/types.ts | 8 +- src/utilities/index.ts | 1 + src/utilities/types/RemoveIndexSignature.ts | 6 + 21 files changed, 279 insertions(+), 47 deletions(-) create mode 100644 .changeset/friendly-papayas-breathe.md create mode 100644 .changeset/happy-weeks-buy.md create mode 100644 .changeset/three-pandas-smash.md create mode 100644 src/utilities/types/RemoveIndexSignature.ts diff --git a/.api-reports/api-report-cache.api.md b/.api-reports/api-report-cache.api.md index 72f792334a2..0e90e2b82fc 100644 --- a/.api-reports/api-report-cache.api.md +++ b/.api-reports/api-report-cache.api.md @@ -236,8 +236,11 @@ type CombineIntersection = Exclude>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) export function createFragmentRegistry(...fragments: DocumentNode[]): FragmentRegistryAPI; @@ -757,7 +760,6 @@ export function makeReference(id: string): Reference; // @public (undocumented) export function makeVar(value: T): ReactiveVar; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1033,6 +1035,11 @@ export interface Reference { // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -1109,7 +1116,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-core.api.md b/.api-reports/api-report-core.api.md index cb31ddd4692..a5d7d74745e 100644 --- a/.api-reports/api-report-core.api.md +++ b/.api-reports/api-report-core.api.md @@ -479,8 +479,11 @@ type ConcastSourcesIterable = Iterable>; // @public (undocumented) export const concat: typeof ApolloLink.concat; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) export const createHttpLink: (linkOptions?: HttpOptions) => ApolloLink; @@ -1401,7 +1404,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts // @@ -2170,6 +2172,11 @@ export type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -2406,7 +2413,7 @@ export type Unmasked = true extends IsAny ? TData : TData extends // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-masking.api.md b/.api-reports/api-report-masking.api.md index 0d22ad2fe1b..12d24672ff5 100644 --- a/.api-reports/api-report-masking.api.md +++ b/.api-reports/api-report-masking.api.md @@ -220,8 +220,11 @@ type CombineIntersection = Exclude>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) export interface DataMasking { @@ -429,7 +432,6 @@ export function maskFragment(data: TData, document: TypedDocume // @internal (undocumented) export function maskOperation(data: TData, document: DocumentNode | TypedDocumentNode, cache: ApolloCache): TData; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts // @@ -558,6 +560,11 @@ interface Reference { // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -608,7 +615,7 @@ export type Unmasked = true extends IsAny ? TData : TData extends // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-react.api.md b/.api-reports/api-report-react.api.md index 8373acf4521..8f302c82f85 100644 --- a/.api-reports/api-report-react.api.md +++ b/.api-reports/api-report-react.api.md @@ -577,8 +577,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) export interface Context extends Record { @@ -1146,7 +1149,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1955,6 +1957,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -2202,7 +2209,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-react_components.api.md b/.api-reports/api-report-react_components.api.md index c9ea4d9100a..739af65d3b8 100644 --- a/.api-reports/api-report-react_components.api.md +++ b/.api-reports/api-report-react_components.api.md @@ -523,8 +523,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) interface DataMasking { @@ -1009,7 +1012,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1737,6 +1739,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -1935,7 +1942,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-react_context.api.md b/.api-reports/api-report-react_context.api.md index c9d716e731e..812f228974f 100644 --- a/.api-reports/api-report-react_context.api.md +++ b/.api-reports/api-report-react_context.api.md @@ -517,8 +517,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) interface DataMasking { @@ -1006,7 +1009,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1665,6 +1667,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -1855,7 +1862,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-react_hoc.api.md b/.api-reports/api-report-react_hoc.api.md index 7579701495f..e05e2f61121 100644 --- a/.api-reports/api-report-react_hoc.api.md +++ b/.api-reports/api-report-react_hoc.api.md @@ -506,8 +506,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) interface DataMasking { @@ -1013,7 +1016,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1694,6 +1696,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -1859,7 +1866,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-react_hooks.api.md b/.api-reports/api-report-react_hooks.api.md index b639caed65d..da083a0abd7 100644 --- a/.api-reports/api-report-react_hooks.api.md +++ b/.api-reports/api-report-react_hooks.api.md @@ -546,8 +546,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) interface DataMasking { @@ -1095,7 +1098,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1814,6 +1816,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -2025,7 +2032,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-react_internal.api.md b/.api-reports/api-report-react_internal.api.md index f5587b3de51..dd6f0073fe5 100644 --- a/.api-reports/api-report-react_internal.api.md +++ b/.api-reports/api-report-react_internal.api.md @@ -525,8 +525,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // Warning: (ae-forgotten-export) The symbol "PreloadQueryFunction" needs to be exported by the entry point index.d.ts // @@ -1105,7 +1108,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1867,6 +1869,11 @@ interface RejectedPromise extends Promise { // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -2077,7 +2084,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-react_ssr.api.md b/.api-reports/api-report-react_ssr.api.md index cb40f4d1f28..b122eff81ce 100644 --- a/.api-reports/api-report-react_ssr.api.md +++ b/.api-reports/api-report-react_ssr.api.md @@ -486,8 +486,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) interface DataMasking { @@ -991,7 +994,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1650,6 +1652,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -1840,7 +1847,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-testing.api.md b/.api-reports/api-report-testing.api.md index 00f01de37dd..c38f15e8bf7 100644 --- a/.api-reports/api-report-testing.api.md +++ b/.api-reports/api-report-testing.api.md @@ -476,8 +476,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @internal (undocumented) type CovariantUnaryFunction = { @@ -980,7 +983,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1715,6 +1717,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -1891,7 +1898,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-testing_core.api.md b/.api-reports/api-report-testing_core.api.md index 1606498c68a..884f6b13152 100644 --- a/.api-reports/api-report-testing_core.api.md +++ b/.api-reports/api-report-testing_core.api.md @@ -475,8 +475,11 @@ class Concast extends Observable { // @public (undocumented) type ConcastSourcesIterable = Iterable>; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @internal (undocumented) type CovariantUnaryFunction = { @@ -979,7 +982,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -1672,6 +1674,11 @@ type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -1848,7 +1855,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report-utilities.api.md b/.api-reports/api-report-utilities.api.md index 76b0f621592..5cb19b3c19e 100644 --- a/.api-reports/api-report-utilities.api.md +++ b/.api-reports/api-report-utilities.api.md @@ -606,8 +606,10 @@ export type ConcastSourcesIterable = Iterable>; // @public (undocumented) export function concatPagination(keyArgs?: KeyArgs): FieldPolicy; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) export function createFragmentMap(fragments?: FragmentDefinitionNode[]): FragmentMap; @@ -1689,7 +1691,6 @@ type MaybeAsync = T | PromiseLike; // @public (undocumented) export function maybeDeepFreeze(obj: T): T; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataMasking" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts @@ -2519,6 +2520,11 @@ export type RemoveFragmentSpreadConfig = RemoveNodeConfig; // @public (undocumented) export function removeFragmentSpreadFromDocument(config: RemoveFragmentSpreadConfig[], doc: DocumentNode): DocumentNode | null; +// @public (undocumented) +export type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -2770,7 +2776,7 @@ type Unmasked = true extends IsAny ? TData : TData extends object // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.api-reports/api-report.api.md b/.api-reports/api-report.api.md index 3a4bac0f7a6..e91fa9f983f 100644 --- a/.api-reports/api-report.api.md +++ b/.api-reports/api-report.api.md @@ -576,8 +576,11 @@ type ConcastSourcesIterable = Iterable>; // @public (undocumented) export const concat: typeof ApolloLink.concat; +// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RemoveIndexSignature" needs to be exported by the entry point index.d.ts +// // @public (undocumented) -type ContainsFragmentsRefs = TData extends object ? " $fragmentRefs" extends keyof TData ? true : ContainsFragmentsRefs : false; +type ContainsFragmentsRefs = true extends IsAny ? false : TData extends object ? " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; // @public (undocumented) export const createHttpLink: (linkOptions?: HttpOptions) => ApolloLink; @@ -1582,7 +1585,6 @@ interface MaskOperationOptions { // @public (undocumented) type MaybeAsync = T | PromiseLike; -// Warning: (ae-forgotten-export) The symbol "IsAny" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "RemoveMaskedMarker" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ContainsFragmentsRefs" needs to be exported by the entry point index.d.ts // @@ -2552,6 +2554,11 @@ export type RefetchWritePolicy = "merge" | "overwrite"; // @public (undocumented) type RemoveFragmentName = T extends any ? Omit : T; +// @public (undocumented) +type RemoveIndexSignature = { + [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K]; +}; + // @public (undocumented) type RemoveMaskedMarker = Omit; @@ -2871,7 +2878,7 @@ export type Unmasked = true extends IsAny ? TData : TData extends // @public (undocumented) type UnwrapFragmentRefs = true extends IsAny ? TData : TData extends any ? string extends keyof TData ? TData : keyof TData extends never ? TData : TData extends { " $fragmentRefs"?: infer FragmentRefs; -} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends Array ? Array> : TData extends object ? { +} ? UnwrapFragmentRefs | RemoveFragmentName[keyof NonNullable]>>>> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; } : TData : never; diff --git a/.changeset/friendly-papayas-breathe.md b/.changeset/friendly-papayas-breathe.md new file mode 100644 index 00000000000..7fb105b6f3c --- /dev/null +++ b/.changeset/friendly-papayas-breathe.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Fix `Unmasked` unwrapping tuple types into an array of their subtypes. diff --git a/.changeset/happy-weeks-buy.md b/.changeset/happy-weeks-buy.md new file mode 100644 index 00000000000..61d9f4eb21d --- /dev/null +++ b/.changeset/happy-weeks-buy.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Ensure `MaybeMasked` does not try and unwrap types that contain index signatures. diff --git a/.changeset/three-pandas-smash.md b/.changeset/three-pandas-smash.md new file mode 100644 index 00000000000..97c1cc673ed --- /dev/null +++ b/.changeset/three-pandas-smash.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Ensure `MaybeMasked` does not try to unwrap the type as `Unmasked` if the type contains `any`. diff --git a/src/masking/__benches__/types.bench.ts b/src/masking/__benches__/types.bench.ts index 621fb29dfaf..c96231a96af 100644 --- a/src/masking/__benches__/types.bench.ts +++ b/src/masking/__benches__/types.bench.ts @@ -299,7 +299,7 @@ test("MaybeMasked handles odd types", (prefix) => { bench(prefix + "unknown instantiations", () => { attest>(); - }).types([52, "instantiations"]); + }).types([54, "instantiations"]); bench(prefix + "unknown functionality", () => { expectTypeOf>().toBeUnknown(); }); @@ -464,3 +464,116 @@ test("base type, multiple fragments on sub-types", (prefix) => { }>(); }); }); + +test("does not detect `$fragmentRefs` if type contains `any`", (prefix) => { + interface Source { + foo: { bar: any[] }; + " $fragmentName": "foo"; + } + + bench(prefix + "instantiations", () => { + return {} as MaybeMasked; + }).types([6, "instantiations"]); + + bench(prefix + "functionality", () => { + const x = {} as MaybeMasked; + + expectTypeOf(x).branded.toEqualTypeOf(); + }); +}); + +test("leaves tuples alone", (prefix) => { + interface Source { + coords: [long: number, lat: number]; + } + + bench(prefix + "instantiations", () => { + return {} as Unmasked; + }).types([5, "instantiations"]); + + bench(prefix + "functionality", () => { + const x = {} as Unmasked; + + expectTypeOf(x).branded.toEqualTypeOf<{ + coords: [long: number, lat: number]; + }>(); + }); +}); + +test("does not detect `$fragmentRefs` if type is a record type", (prefix) => { + interface MetadataItem { + foo: string; + } + + interface Source { + metadata: Record; + " $fragmentName": "Source"; + } + + bench(prefix + "instantiations", () => { + return {} as MaybeMasked; + }).types([6, "instantiations"]); + + bench(prefix + "functionality", () => { + const x = {} as MaybeMasked; + + expectTypeOf(x).branded.toEqualTypeOf(); + }); +}); + +test("does not detect `$fragmentRefs` on types with index signatures", (prefix) => { + interface Source { + foo: string; + " $fragmentName": "Source"; + [key: string]: string; + } + + bench(prefix + "instantiations", () => { + return {} as MaybeMasked; + }).types([6, "instantiations"]); + + bench(prefix + "functionality", () => { + const x = {} as MaybeMasked; + + expectTypeOf(x).branded.toEqualTypeOf(); + }); +}); + +test("detects `$fragmentRefs` on types with index signatures", (prefix) => { + type Source = { + __typename: "Foo"; + id: number; + metadata: Record; + structuredMetadata: StructuredMetadata; + } & { " $fragmentName"?: "UserFieldsFragment" } & { + " $fragmentRefs"?: { + FooFragment: FooFragment; + }; + }; + + interface StructuredMetadata { + bar: number; + [index: string]: number; + } + + type FooFragment = { + __typename: "Foo"; + foo: string; + } & { " $fragmentName"?: "FooFragment" }; + + bench(prefix + "instantiations", () => { + return {} as MaybeMasked; + }).types([6, "instantiations"]); + + bench(prefix + "functionality", () => { + const x = {} as MaybeMasked; + + expectTypeOf(x).branded.toEqualTypeOf<{ + __typename: "Foo"; + id: number; + metadata: Record; + foo: string; + structuredMetadata: StructuredMetadata; + }>(); + }); +}); diff --git a/src/masking/internal/types.ts b/src/masking/internal/types.ts index ead6b64abdf..4c769de426d 100644 --- a/src/masking/internal/types.ts +++ b/src/masking/internal/types.ts @@ -1,4 +1,4 @@ -import type { Prettify } from "../../utilities/index.js"; +import type { Prettify, RemoveIndexSignature } from "../../utilities/index.js"; export type IsAny = 0 extends 1 & T ? true : false; @@ -20,7 +20,6 @@ export type UnwrapFragmentRefs = > > > - : TData extends Array ? Array> : TData extends object ? { [K in keyof TData]: UnwrapFragmentRefs; @@ -184,8 +183,9 @@ export type RemoveFragmentName = T extends any ? Omit : T; export type ContainsFragmentsRefs = - TData extends object ? - " $fragmentRefs" extends keyof TData ? + true extends IsAny ? false + : TData extends object ? + " $fragmentRefs" extends keyof RemoveIndexSignature ? true : ContainsFragmentsRefs : false; diff --git a/src/utilities/index.ts b/src/utilities/index.ts index 300cafb0d56..f4e7705deb6 100644 --- a/src/utilities/index.ts +++ b/src/utilities/index.ts @@ -139,6 +139,7 @@ export type { OnlyRequiredProperties } from "./types/OnlyRequiredProperties.js"; export type { Prettify } from "./types/Prettify.js"; export type { UnionToIntersection } from "./types/UnionToIntersection.js"; export type { NoInfer } from "./types/NoInfer.js"; +export type { RemoveIndexSignature } from "./types/RemoveIndexSignature.js"; export { AutoCleanedStrongCache, diff --git a/src/utilities/types/RemoveIndexSignature.ts b/src/utilities/types/RemoveIndexSignature.ts new file mode 100644 index 00000000000..4aad90687d9 --- /dev/null +++ b/src/utilities/types/RemoveIndexSignature.ts @@ -0,0 +1,6 @@ +export type RemoveIndexSignature = { + [K in keyof T as string extends K ? never + : number extends K ? never + : symbol extends K ? never + : K]: T[K]; +};