Skip to content

Can not create type of svelte-form's createAppForm with typed form data #1966

@danielclausmeyer

Description

@danielclausmeyer

Describe the bug

Creating a type of a form, like its shown in the Svelte example, does not work.

You are supposed to be able to create a type of the return value of createAppForm with default values used in form components like so:

import { createFormCreator, formOptions } from "@tanstack/svelte-form";
import TextField from "../components/text-field.svelte";
import SubscribeButton from "../components/subscribe-button.svelte";

const { createAppForm } = createFormCreator({
  fieldComponents: {
    TextField,
  },
  formComponents: {
    SubscribeButton,
  },
});

const peopleFormOpts = formOptions({
  defaultValues: {
    fullName: "",
    email: "",
    phone: "",
  },
});

type Form = ReturnType<typeof createAppForm<typeof peopleFormOpts.defaultValues>>;

But this fails because Type '<TFormData, TOnMount extends FormValidateOrFn<TFormData> | undefined, TOnChange extends FormValidateOrFn<TFormData> | undefined, TOnChangeAsync extends FormAsyncValidateOrFn<TFormData> | undefined, TOnBlur extends FormValidateOrFn<...> | undefined, TOnBlurAsync extends FormAsyncValidateOrFn<...> | undefined, TOnSubm...' has no signatures for which the type argument list is applicable.ts(2635)

You have to define all the other generics as well to make the type accept the argument list. Looking at the definition for createAppForm it would look something like this:

type DefaultValues = typeof peopleFormOpts.defaultValues

type Form = ReturnType<
  typeof createAppForm<
    DefaultValues,
    FormValidateOrFn<DefaultValues>,
    FormValidateOrFn<DefaultValues>,
    FormAsyncValidateOrFn<DefaultValues>,
    FormValidateOrFn<DefaultValues>,
    FormAsyncValidateOrFn<DefaultValues>,
    FormValidateOrFn<DefaultValues>,
    FormAsyncValidateOrFn<DefaultValues>,
    FormValidateOrFn<DefaultValues>,
    FormAsyncValidateOrFn<DefaultValues>,
    FormAsyncValidateOrFn<DefaultValues>,
    any
  >
>

This is accepted, but its obviously impractical to repeat in each form component and there are also differences between this type and the actual return type of calling createAppForm. The only solution seems to be using any for everything but the default values.

I created a helper type for this. It works, all the fields are typed correctly. But i feel like there could be missing some information that depends on the given input of createAppForm which is not included in this. I haven't noticed this yet but looking at the definition it seems to be a possibility.

export type AppForm<Data extends any> = ReturnType<
  typeof createAppForm<
    Data,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any,
    any
  >
>

/* Usage */

type Form = AppForm<typeof peopleFormOpts.defaultValues>

What do you think about this solution? Is that what we should do or can we "fix" the types to make it work like in your "large-form" example?

Your minimal, reproducible example

Code Sandbox from Tanstack Form Docs

Steps to reproduce

  1. Go to https://codesandbox.io/p/devbox/github/tanstack/form/tree/main/examples/svelte/large-form?embed=1&theme=light&file=src/App.svelte
  2. Install Svelte for VS Code extension or svelte-check
  3. Check address-fields.svelte file

Expected behavior

I should be able to create a type of a form with default values to be able to do form composition.

How often does this bug happen?

Every time

Screenshots or Videos

Example from the docs running in code sandbox:

Image

Working types with any solution:

Image

Platform

  • OS: macOS (But happens anywhere)
  • Browser: Chrome (But its a type issue)
  • Version: 143.0.7499.170

TanStack Form adapter

svelte-form

TanStack Form version

1.27.7

TypeScript version

5.9.2

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions