From cb8d079f49a2236f4b3407adaff873673e5c214e Mon Sep 17 00:00:00 2001 From: mtt-artis Date: Wed, 28 Jan 2026 22:27:05 +0100 Subject: [PATCH 1/2] feat(createServerFn): allow FormData union type --- .../start-client-core/src/createServerFn.ts | 2 +- .../src/tests/createServerFn.test-d.ts | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/start-client-core/src/createServerFn.ts b/packages/start-client-core/src/createServerFn.ts index 39542d1e2a1..c3f444c28ff 100644 --- a/packages/start-client-core/src/createServerFn.ts +++ b/packages/start-client-core/src/createServerFn.ts @@ -468,7 +468,7 @@ export type ValidateValidatorInput< TMethod extends Method, TInputValidator, > = TMethod extends 'POST' - ? ResolveValidatorInput extends FormData + ? FormData extends ResolveValidatorInput ? ResolveValidatorInput : ValidateSerializable< ResolveValidatorInput, diff --git a/packages/start-client-core/src/tests/createServerFn.test-d.ts b/packages/start-client-core/src/tests/createServerFn.test-d.ts index f0cb181a43d..2ba7f7a8fa1 100644 --- a/packages/start-client-core/src/tests/createServerFn.test-d.ts +++ b/packages/start-client-core/src/tests/createServerFn.test-d.ts @@ -879,3 +879,25 @@ test('createServerFn respects TsrSerializable', () => { Promise<{ nested: { custom: MyCustomTypeSerializable } }> >() }) + +test('createServerFn POST with FormData union validator', () => { + const validator = createServerFn({ method: 'POST' }).inputValidator< + (input: FormData | { id: string }) => { id: 'string' } + > + + expectTypeOf(validator) + .parameter(0) + .parameter(0) + .toEqualTypeOf() +}) + +test('createServerFn GET cannot use FormData union validator', () => { + const validator = createServerFn({ method: 'GET' }).inputValidator< + (input: FormData | { id: string }) => { output: 'string' } + > + + expectTypeOf(validator) + .parameter(0) + .parameter(0) + .not.toEqualTypeOf() +}) From ab4c68305176cf70f0d470891b03fd9a702d0967 Mon Sep 17 00:00:00 2001 From: mtt-artis Date: Thu, 29 Jan 2026 00:07:23 +0100 Subject: [PATCH 2/2] fix(createServerFn): add regression test --- .../start-client-core/src/createServerFn.ts | 13 ++++--- .../src/tests/createServerFn.test-d.ts | 35 ++++++++++++++++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/start-client-core/src/createServerFn.ts b/packages/start-client-core/src/createServerFn.ts index c3f444c28ff..08e394eaf72 100644 --- a/packages/start-client-core/src/createServerFn.ts +++ b/packages/start-client-core/src/createServerFn.ts @@ -468,12 +468,17 @@ export type ValidateValidatorInput< TMethod extends Method, TInputValidator, > = TMethod extends 'POST' - ? FormData extends ResolveValidatorInput - ? ResolveValidatorInput - : ValidateSerializable< - ResolveValidatorInput, + ? Extract, FormData> extends never + ? ValidateSerializable< + Exclude, FormData>, RegisteredSerializableInput > + : + | FormData + | ValidateSerializable< + Exclude, FormData>, + RegisteredSerializableInput + > : ValidateSerializable< ResolveValidatorInput, RegisteredSerializableInput diff --git a/packages/start-client-core/src/tests/createServerFn.test-d.ts b/packages/start-client-core/src/tests/createServerFn.test-d.ts index 2ba7f7a8fa1..82dd3fd704d 100644 --- a/packages/start-client-core/src/tests/createServerFn.test-d.ts +++ b/packages/start-client-core/src/tests/createServerFn.test-d.ts @@ -896,8 +896,35 @@ test('createServerFn GET cannot use FormData union validator', () => { (input: FormData | { id: string }) => { output: 'string' } > - expectTypeOf(validator) - .parameter(0) - .parameter(0) - .not.toEqualTypeOf() + expectTypeOf(validator).parameter(0).parameter(0).toEqualTypeOf< + | { + append: 'Function is not serializable' + delete: 'Function is not serializable' + get: 'Function is not serializable' + getAll: 'Function is not serializable' + has: 'Function is not serializable' + set: 'Function is not serializable' + forEach: 'Function is not serializable' + entries: 'Function is not serializable' + keys: 'Function is not serializable' + values: 'Function is not serializable' + [Symbol.iterator]: 'Function is not serializable' + } + | { + id: string + } + >() +}) + +test('createServerFn POST rejects FormData union with non-serializable', () => { + const validator = createServerFn({ method: 'POST' }).inputValidator< + (input: FormData | { func: () => void }) => { output: 'string' } + > + + expectTypeOf(validator).parameter(0).parameter(0).toEqualTypeOf< + | FormData + | { + func: 'Function is not serializable' + } + >() })