diff --git a/.changeset/shaky-bobcats-dig.md b/.changeset/shaky-bobcats-dig.md new file mode 100644 index 000000000000..09007d960285 --- /dev/null +++ b/.changeset/shaky-bobcats-dig.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: improves fields type for generic components diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index fd41c98481d5..200ae665893f 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -15,7 +15,8 @@ import { PrerenderUnseenRoutesHandlerValue, PrerenderOption, RequestOptions, - RouteSegment + RouteSegment, + IsAny } from '../types/private.js'; import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from 'types'; import { SvelteConfig } from '@sveltejs/vite-plugin-svelte'; @@ -1953,6 +1954,18 @@ type UnknownField = RemoteFormFieldMethods & { [key: string | number]: UnknownField; }; +type RemoteFormFieldsRoot = + IsAny extends true + ? RecursiveFormFields + : Input extends void + ? { + /** Validation issues, if any */ + issues(): RemoteFormIssue[] | undefined; + /** Validation issues belonging to this or any of the fields that belong to it, if any */ + allIssues(): RemoteFormIssue[] | undefined; + } + : RemoteFormFields; + /** * Recursive type to build form fields structure with proxy access */ @@ -2077,7 +2090,7 @@ export type RemoteForm = { /** The number of pending submissions */ get pending(): number; /** Access form fields using object notation */ - fields: RemoteFormFields; + fields: RemoteFormFieldsRoot; }; /** diff --git a/packages/kit/src/types/private.d.ts b/packages/kit/src/types/private.d.ts index da512ed777c5..d5dbd64a80ff 100644 --- a/packages/kit/src/types/private.d.ts +++ b/packages/kit/src/types/private.d.ts @@ -241,3 +241,5 @@ export interface RouteSegment { } export type TrailingSlash = 'never' | 'always' | 'ignore'; + +export type IsAny = 0 extends 1 & T ? true : false; diff --git a/packages/kit/test/types/remote.test.ts b/packages/kit/test/types/remote.test.ts index e30f43fc17d8..e428dcbcfdcd 100644 --- a/packages/kit/test/types/remote.test.ts +++ b/packages/kit/test/types/remote.test.ts @@ -1,6 +1,12 @@ import { query, prerender, command, form } from '$app/server'; import { StandardSchemaV1 } from '@standard-schema/spec'; -import { RemotePrerenderFunction, RemoteQueryFunction, invalid } from '@sveltejs/kit'; +import { + RemoteForm, + RemoteFormInput, + RemotePrerenderFunction, + RemoteQueryFunction, + invalid +} from '@sveltejs/kit'; const schema: StandardSchemaV1 = null as any; const schema2: StandardSchemaV1 = null as any; @@ -359,6 +365,16 @@ function form_tests() { // doesn't use data const f9 = form(() => Promise.resolve({ success: true })); f9.result?.success === true; + + // generic form + function f10< + Schema extends StandardSchemaV1, + Form extends RemoteForm, unknown> + >(data: StandardSchemaV1.InferInput, form: Form) { + form.fields.set(data); + form.fields.allIssues(); + } + void f10; } form_tests(); diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 30d5e82f91c8..b301ec99186a 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1929,6 +1929,18 @@ declare module '@sveltejs/kit' { [key: string | number]: UnknownField; }; + type RemoteFormFieldsRoot = + IsAny extends true + ? RecursiveFormFields + : Input extends void + ? { + /** Validation issues, if any */ + issues(): RemoteFormIssue[] | undefined; + /** Validation issues belonging to this or any of the fields that belong to it, if any */ + allIssues(): RemoteFormIssue[] | undefined; + } + : RemoteFormFields; + /** * Recursive type to build form fields structure with proxy access */ @@ -2053,7 +2065,7 @@ declare module '@sveltejs/kit' { /** The number of pending submissions */ get pending(): number; /** Access form fields using object notation */ - fields: RemoteFormFields; + fields: RemoteFormFieldsRoot; }; /** @@ -2371,6 +2383,8 @@ declare module '@sveltejs/kit' { } type TrailingSlash = 'never' | 'always' | 'ignore'; + + type IsAny = 0 extends 1 & T ? true : false; interface Asset { file: string; size: number;