TanStack / TanStack/form

Type inference not working for createServerValidate with Standard Schema (Zod)

Open
#1,856 2 comments 9 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

v1 v2: needs investigation
Dominant language
TypeScript
Stars
6.7k
Forks
682
Avg merge
5d 18h
Merged PRs (30d)
7

Description

Description

When using createServerValidate from @tanstack/react-form-start with Zod schemas (which implement Standard Schema v1), the return type is Promise<any> instead of inferring the output type from the schema.

Since TanStack Form v1.0+ supports Standard Schema natively, and Zod v4+ properly implements the Standard Schema spec with type information available via StandardSchemaV1.InferOutput, I would expect createServerValidate to infer the validated data type automatically.

Environment

  • @tanstack/react-form-start: 1.25.0
  • @tanstack/form-core: 1.25.0
  • zod: 4.1.12
  • TypeScript: (affects all versions)

Current Behavior

import { createServerValidate, formOptions } from '@tanstack/react-form-start';
import { z } from 'zod';

const emailFormOpts = formOptions({
  defaultValues: {
    email: '',
  },
});

const loginSchema = z.object({
  email: z.string().email(),
  redirect: z.string().default('/'),
});

const serverValidate = createServerValidate({
  ...emailFormOpts,
  onServerValidate: loginSchema,
});

// Type is inferred as Promise<any> instead of Promise<{ email: string; redirect: string }>
const validatedData = await serverValidate(formData);
//    ^? any

Expected Behavior

The return type should be inferred from the Zod schema:

const validatedData = await serverValidate(formData);
//    ^? { email: string; redirect: string }

Root Cause Analysis

After investigating the source code:

1. Type Definition Returns Promise<any>

From createServerValidate.d.ts:

export declare const createServerValidate: <TFormData, ...>(
  defaultOpts: CreateServerValidateOptions<...>
) => (formData: FormData, info?: Parameters<typeof decode>[1]) => Promise<any>;
2. Type Information IS Available

Zod v4's Standard Schema implementation provides type information:

export interface StandardSchemaV1<Input = unknown, Output = Input> {
  readonly "~standard": StandardSchemaV1.Props<Input, Output>;
}

export declare namespace StandardSchemaV1 {
  export type InferOutput<Schema extends StandardSchemaV1> =
    NonNullable<Schema["~standard"]["types"]>["output"];
}
3. TanStack Form Only Extracts Error Types

From @tanstack/form-core/src/FormApi.ts:

export type UnwrapFormAsyncValidateOrFn<
  TValidateOrFn extends undefined | FormAsyncValidateOrFn<any>,
> = [TValidateOrFn] extends [StandardSchemaV1<any, any>]
    ? Record<string, StandardSchemaV1Issue[]>  // Only extracts error type!
    : undefined

The library only extracts validation errors from Standard Schema validators, not the output data type.

Proposed Solution

Create a utility type to extract the output type from Standard Schema validators:

type InferValidatorOutput<TValidator> =
  TValidator extends StandardSchemaV1<any, infer Output>
    ? Output
    : TValidator extends FormValidateAsyncFn<infer TFormData>
      ? TFormData
      : unknown;

Then update createServerValidate's return type to use Promise<InferValidatorOutput<TOnServer>> instead of Promise<any>.

Current Workaround

Users must manually assert the type:

import type { StandardSchemaV1 } from 'zod';

const validatedData = await serverValidate(formData) as StandardSchemaV1.InferOutput<typeof loginSchema>;

// Or using z.infer:
const validatedData = await serverValidate(formData) as z.infer<typeof loginSchema>;

Impact

This affects all users of createServerValidate with Standard Schema validators (Zod, Valibot, ArkType, etc.). Type safety is lost at the boundary between form validation and business logic, requiring manual type assertions throughout the codebase.

Additional Context

This appears to be an oversight rather than intentional design, as:

  1. TanStack Form explicitly supports Standard Schema
  2. Standard Schema provides full type information via ~standard.types
  3. The validated data is returned at runtime with full type information
  4. Only the TypeScript type definition is missing the connection

Would the maintainers be open to a PR implementing this type inference? I'm happy to contribute if this aligns with the project's direction.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in createServerValidate.d.ts, then compare its return type with Standard Schema handling in @tanstack/form-core/src/FormApi.ts. Use the included Zod example to verify that the awaited result is inferred as the schema output rather than any, while preserving the existing validator behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, developer-experience
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.