From 12c6bfb3139e37901ed5a545b45f6172e21a30b2 Mon Sep 17 00:00:00 2001 From: Matt DeKok Date: Wed, 15 Oct 2025 13:52:09 -0500 Subject: [PATCH 1/3] fix: `RecursiveFormFields` type for recursive or unknown schemas --- .changeset/upset-hotels-mix.md | 5 +++++ packages/kit/src/exports/public.d.ts | 22 +++++++++++++++++----- packages/kit/types/index.d.ts | 22 +++++++++++++++++----- 3 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 .changeset/upset-hotels-mix.md diff --git a/.changeset/upset-hotels-mix.md b/.changeset/upset-hotels-mix.md new file mode 100644 index 000000000000..45b003eadee2 --- /dev/null +++ b/.changeset/upset-hotels-mix.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: `RecursiveFormFields` type for recursive or unknown schemas diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 01e4f8cf9eb9..18ed911e8302 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1917,19 +1917,31 @@ type RemoteFormFieldContainer = RemoteFormFieldMethods & { /** * Recursive type to build form fields structure with proxy access */ -type RemoteFormFields = +export type RemoteFormFields = WillRecurseIndefinitely extends true - ? RecursiveFormFields + ? RecursiveFormFields : NonNullable extends string | number | boolean | File ? RemoteFormField> : T extends string[] | File[] ? RemoteFormField & { [K in number]: RemoteFormField } : T extends Array - ? RemoteFormFieldContainer & { [K in number]: RemoteFormFields } - : RemoteFormFieldContainer & { [K in keyof T]-?: RemoteFormFields }; + ? RemoteFormFieldContainer & { + [K in number]: RemoteFormFields< + U, + U extends RemoteFormFieldValue | unknown ? true : false + >; + } + : RemoteFormFieldContainer & { + [K in keyof T]-?: RemoteFormFields< + T[K], + T[K] extends RemoteFormFieldValue | unknown ? true : false + >; + }; // By breaking this out into its own type, we avoid the TS recursion depth limit -type RecursiveFormFields = RemoteFormField & { [key: string | number]: RecursiveFormFields }; +type RecursiveFormFields = (Leaf extends true + ? RemoteFormField + : RemoteFormFieldContainer) & { [key: string | number]: RecursiveFormFields }; type MaybeArray = T | T[]; diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index b503853794e8..e04c0dd4d082 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1893,19 +1893,31 @@ declare module '@sveltejs/kit' { /** * Recursive type to build form fields structure with proxy access */ - type RemoteFormFields = + export type RemoteFormFields = WillRecurseIndefinitely extends true - ? RecursiveFormFields + ? RecursiveFormFields : NonNullable extends string | number | boolean | File ? RemoteFormField> : T extends string[] | File[] ? RemoteFormField & { [K in number]: RemoteFormField } : T extends Array - ? RemoteFormFieldContainer & { [K in number]: RemoteFormFields } - : RemoteFormFieldContainer & { [K in keyof T]-?: RemoteFormFields }; + ? RemoteFormFieldContainer & { + [K in number]: RemoteFormFields< + U, + U extends RemoteFormFieldValue | unknown ? true : false + >; + } + : RemoteFormFieldContainer & { + [K in keyof T]-?: RemoteFormFields< + T[K], + T[K] extends RemoteFormFieldValue | unknown ? true : false + >; + }; // By breaking this out into its own type, we avoid the TS recursion depth limit - type RecursiveFormFields = RemoteFormField & { [key: string | number]: RecursiveFormFields }; + type RecursiveFormFields = (Leaf extends true + ? RemoteFormField + : RemoteFormFieldContainer) & { [key: string | number]: RecursiveFormFields }; type MaybeArray = T | T[]; From b15abcbb0825a17c37ae0a4e6d489ef7a748de43 Mon Sep 17 00:00:00 2001 From: Matt DeKok Date: Sun, 19 Oct 2025 17:28:24 -0500 Subject: [PATCH 2/3] fix: better recursive unknown fields --- packages/kit/src/exports/public.d.ts | 39 ++++++++++++++++++---------- packages/kit/types/index.d.ts | 39 ++++++++++++++++++---------- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 18ed911e8302..7f9a6f05ba00 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1914,34 +1914,47 @@ type RemoteFormFieldContainer = RemoteFormFieldMethods & { allIssues(): RemoteFormIssue[] | undefined; }; +type UnknownField = RemoteFormFieldMethods & { + /** Validation issues belonging to this or any of the fields that belong to it, if any */ + allIssues(): RemoteFormIssue[] | undefined; +} & { + /** + * Returns an object that can be spread onto an input element with the correct type attribute, + * aria-invalid attribute if the field is invalid, and appropriate value/checked property getters/setters. + * @example + * ```svelte + * + * + * + * ``` + */ + as>(...args: AsArgs): InputElementProps; +} & { + [key: string | number]: UnknownField; +}; + /** * Recursive type to build form fields structure with proxy access */ -export type RemoteFormFields = +export type RemoteFormFields = WillRecurseIndefinitely extends true - ? RecursiveFormFields + ? RecursiveFormFields : NonNullable extends string | number | boolean | File ? RemoteFormField> : T extends string[] | File[] ? RemoteFormField & { [K in number]: RemoteFormField } : T extends Array ? RemoteFormFieldContainer & { - [K in number]: RemoteFormFields< - U, - U extends RemoteFormFieldValue | unknown ? true : false - >; + [K in number]: RemoteFormFields; } : RemoteFormFieldContainer & { - [K in keyof T]-?: RemoteFormFields< - T[K], - T[K] extends RemoteFormFieldValue | unknown ? true : false - >; + [K in keyof T]-?: RemoteFormFields; }; // By breaking this out into its own type, we avoid the TS recursion depth limit -type RecursiveFormFields = (Leaf extends true - ? RemoteFormField - : RemoteFormFieldContainer) & { [key: string | number]: RecursiveFormFields }; +type RecursiveFormFields = RemoteFormFieldContainer & { + [key: string | number]: UnknownField; +}; type MaybeArray = T | T[]; diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 1e4b415b0ab0..b99394c4efc5 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1890,34 +1890,47 @@ declare module '@sveltejs/kit' { allIssues(): RemoteFormIssue[] | undefined; }; + type UnknownField = RemoteFormFieldMethods & { + /** Validation issues belonging to this or any of the fields that belong to it, if any */ + allIssues(): RemoteFormIssue[] | undefined; + } & { + /** + * Returns an object that can be spread onto an input element with the correct type attribute, + * aria-invalid attribute if the field is invalid, and appropriate value/checked property getters/setters. + * @example + * ```svelte + * + * + * + * ``` + */ + as>(...args: AsArgs): InputElementProps; + } & { + [key: string | number]: UnknownField; + }; + /** * Recursive type to build form fields structure with proxy access */ - export type RemoteFormFields = + export type RemoteFormFields = WillRecurseIndefinitely extends true - ? RecursiveFormFields + ? RecursiveFormFields : NonNullable extends string | number | boolean | File ? RemoteFormField> : T extends string[] | File[] ? RemoteFormField & { [K in number]: RemoteFormField } : T extends Array ? RemoteFormFieldContainer & { - [K in number]: RemoteFormFields< - U, - U extends RemoteFormFieldValue | unknown ? true : false - >; + [K in number]: RemoteFormFields; } : RemoteFormFieldContainer & { - [K in keyof T]-?: RemoteFormFields< - T[K], - T[K] extends RemoteFormFieldValue | unknown ? true : false - >; + [K in keyof T]-?: RemoteFormFields; }; // By breaking this out into its own type, we avoid the TS recursion depth limit - type RecursiveFormFields = (Leaf extends true - ? RemoteFormField - : RemoteFormFieldContainer) & { [key: string | number]: RecursiveFormFields }; + type RecursiveFormFields = RemoteFormFieldContainer & { + [key: string | number]: UnknownField; + }; type MaybeArray = T | T[]; From c3be7cc15c56cecd70c8e7253883d3797e289d8f Mon Sep 17 00:00:00 2001 From: Matt DeKok Date: Sun, 19 Oct 2025 19:47:04 -0500 Subject: [PATCH 3/3] simplify type --- packages/kit/src/exports/public.d.ts | 1 - packages/kit/types/index.d.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 77ea2507c15d..cb42dc6cc1c0 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1917,7 +1917,6 @@ type RemoteFormFieldContainer = RemoteFormFieldMethods & { type UnknownField = RemoteFormFieldMethods & { /** Validation issues belonging to this or any of the fields that belong to it, if any */ allIssues(): RemoteFormIssue[] | undefined; -} & { /** * Returns an object that can be spread onto an input element with the correct type attribute, * aria-invalid attribute if the field is invalid, and appropriate value/checked property getters/setters. diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index ba5b858dcbe2..52fcb547490d 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1893,7 +1893,6 @@ declare module '@sveltejs/kit' { type UnknownField = RemoteFormFieldMethods & { /** Validation issues belonging to this or any of the fields that belong to it, if any */ allIssues(): RemoteFormIssue[] | undefined; - } & { /** * Returns an object that can be spread onto an input element with the correct type attribute, * aria-invalid attribute if the field is invalid, and appropriate value/checked property getters/setters.