From d8d8ad1a1c16e074d2ea261f900232749be26231 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Mon, 9 Feb 2026 23:23:23 +0100 Subject: [PATCH] fix: allow optional types for remote query/command/prerender functions We're using the `arg: undefined extends Input ? Input | void : Input` method and not the `...args: undefined extends Input ? [arg?: Input] : [arg: Input]` method because the former does work in more cases (the latter throws a type error in our own code around generics), even though the TS team likely wants us to use the latter (but that pattern is in so many code bases now that this behavior around `void` will never change). One drawback (of either method) is that without strict mode all commands/queries/prerenders have optional args now, because `undefined extends X` is always `true` in non-strict mode. But since noone who uses type checking nowadays should use non-strict mode anyway, it's fine. fixes #14500 --- .changeset/violet-things-wear.md | 5 +++ packages/kit/src/exports/public.d.ts | 10 ++++-- packages/kit/test/types/remote.test.ts | 46 ++++++++++++++++++++++++++ packages/kit/types/index.d.ts | 10 ++++-- 4 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 .changeset/violet-things-wear.md diff --git a/.changeset/violet-things-wear.md b/.changeset/violet-things-wear.md new file mode 100644 index 000000000000..33983d0f5e76 --- /dev/null +++ b/.changeset/violet-things-wear.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: allow optional types for remote query/command/prerender functions diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index c6bc1dcce8df..87ce0f28e11c 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -2110,7 +2110,7 @@ export type RemoteForm = { * The return value of a remote `command` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation. */ export type RemoteCommand = { - (arg: Input): Promise> & { + (arg: undefined extends Input ? Input | void : Input): Promise> & { updates(...queries: Array | RemoteQueryOverride>): Promise>; }; /** The number of pending command executions */ @@ -2180,11 +2180,15 @@ export interface RemoteQueryOverride { /** * The return value of a remote `prerender` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#prerender) for full documentation. */ -export type RemotePrerenderFunction = (arg: Input) => RemoteResource; +export type RemotePrerenderFunction = ( + arg: undefined extends Input ? Input | void : Input +) => RemoteResource; /** * The return value of a remote `query` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query) for full documentation. */ -export type RemoteQueryFunction = (arg: Input) => RemoteQuery; +export type RemoteQueryFunction = ( + arg: undefined extends Input ? Input | void : Input +) => RemoteQuery; export * from './index.js'; diff --git a/packages/kit/test/types/remote.test.ts b/packages/kit/test/types/remote.test.ts index e428dcbcfdcd..59439717f43d 100644 --- a/packages/kit/test/types/remote.test.ts +++ b/packages/kit/test/types/remote.test.ts @@ -10,6 +10,7 @@ import { const schema: StandardSchemaV1 = null as any; const schema2: StandardSchemaV1 = null as any; +const schema3: StandardSchemaV1 = null as any; function query_tests() { const no_args: RemoteQueryFunction = query(() => 'Hello world'); @@ -40,6 +41,21 @@ function query_tests() { } void query_without_args(); + async function query_with_optional_arg() { + const q = query(schema3, () => 'Hello world'); + void q(); + void q('hi'); + // @ts-expect-error + void q(1); + + const q2 = query('unchecked', (a?: string) => a); + void q2(); + void q2('hi'); + // @ts-expect-error + void q2(1); + } + void query_with_optional_arg(); + async function query_unsafe() { const q = query('unchecked', (a: number) => a); const result: number = await q(1); @@ -106,6 +122,21 @@ function prerender_tests() { } void prerender_unsafe(); + async function prerender_with_optional_arg() { + const q = prerender(schema3, () => 'Hello world'); + void q(); + void q('hi'); + // @ts-expect-error + void q(1); + + const q2 = prerender('unchecked', (a?: string) => a); + void q2(); + void q2('hi'); + // @ts-expect-error + void q2(1); + } + void prerender_with_optional_arg(); + async function prerender_schema() { const q = prerender(schema, (a) => a); const result: string = await q('1'); @@ -141,6 +172,21 @@ function command_tests() { } void command_without_args(); + async function command_with_optional_arg() { + const q = command(schema3, () => 'Hello world'); + void q(); + void q('hi'); + // @ts-expect-error + void q(1); + + const q2 = command('unchecked', (a?: string) => a); + void q2(); + void q2('hi'); + // @ts-expect-error + void q2(1); + } + void command_with_optional_arg(); + async function command_unsafe() { const cmd = command('unchecked', (a: string) => a); const result: string = await cmd('test'); diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 9db4119631ea..f4b92a6a875e 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -2085,7 +2085,7 @@ declare module '@sveltejs/kit' { * The return value of a remote `command` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation. */ export type RemoteCommand = { - (arg: Input): Promise> & { + (arg: undefined extends Input ? Input | void : Input): Promise> & { updates(...queries: Array | RemoteQueryOverride>): Promise>; }; /** The number of pending command executions */ @@ -2155,12 +2155,16 @@ declare module '@sveltejs/kit' { /** * The return value of a remote `prerender` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#prerender) for full documentation. */ - export type RemotePrerenderFunction = (arg: Input) => RemoteResource; + export type RemotePrerenderFunction = ( + arg: undefined extends Input ? Input | void : Input + ) => RemoteResource; /** * The return value of a remote `query` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query) for full documentation. */ - export type RemoteQueryFunction = (arg: Input) => RemoteQuery; + export type RemoteQueryFunction = ( + arg: undefined extends Input ? Input | void : Input + ) => RemoteQuery; interface AdapterEntry { /** * A string that uniquely identifies an HTTP service (e.g. serverless function) and is used for deduplication.