# TypeScript

Since the library is written in TypeScript and we put a lot of emphasis on the development experience, you can expect maximum TypeScript support. Types are automatically inferred from your <Link href="/svelte/guides/define-your-form/">Valibot schemas</Link>, providing type safety throughout your forms.

## Type inference

Formisch uses Valibot's type inference to automatically derive TypeScript types from your schemas. You don't need to define separate types—they're inferred automatically.

```svelte
<script lang="ts">
  import {
    createForm,
    Field,
    Form,
    type SubmitEventHandler,
  } from '@formisch/svelte';
  import * as v from 'valibot';

  const LoginSchema = v.object({
    email: v.pipe(v.string(), v.email()),
    password: v.pipe(v.string(), v.minLength(8)),
  });

  const loginForm = createForm({
    schema: LoginSchema,
  });

  // TypeScript knows the form structure from the schema
  // loginForm is of type FormStore<typeof LoginSchema>

  const handleSubmit: SubmitEventHandler<typeof LoginSchema> = (
    output,
    _event
  ) => {
    // output is fully typed based on LoginSchema
    console.log(output.email); // ✓ Type-safe
    console.log(output.username); // ✗ TypeScript error
  };
</script>

<Form of={loginForm} onsubmit={handleSubmit}>
  <!-- Form fields -->
</Form>
```

### Input and output types

Valibot schemas can have different input and output types when using transformations. Formisch provides proper typing for both.

```svelte
<script lang="ts">
  import {
    createForm,
    Field,
    Form,
    type SubmitEventHandler,
  } from '@formisch/svelte';
  import * as v from 'valibot';

  const ProfileSchema = v.object({
    age: v.pipe(
      v.string(), // Input type: string (from HTML input)
      v.transform((input) => Number(input)), // Output type: number
      v.number()
    ),
    birthDate: v.pipe(
      v.string(), // Input type: string (ISO date string)
      v.transform((input) => new Date(input)), // Output type: Date
      v.date()
    ),
  });

  const profileForm = createForm({
    schema: ProfileSchema,
  });

  const handleSubmit: SubmitEventHandler<typeof ProfileSchema> = (
    output,
    _event
  ) => {
    // output is: { age: number; birthDate: Date }
    console.log(output.age); // number
    console.log(output.birthDate); // Date
  };
</script>

<Form of={profileForm} onsubmit={handleSubmit}>
  <Field of={profileForm} path={['age']}>
    {#snippet children(field)}
      <!-- field.input is string -->
      <input {...field.props} value={field.input} type="text" />
    {/snippet}
  </Field>

  <Field of={profileForm} path={['birthDate']}>
    {#snippet children(field)}
      <!-- field.input is string -->
      <input {...field.props} value={field.input} type="date" />
    {/snippet}
  </Field>

  <button type="submit">Submit</button>
</Form>
```

### Type-safe paths

Field paths are fully type-checked. TypeScript will provide autocompletion and catch invalid paths at compile time.

```ts
const UserSchema = v.object({
  profile: v.object({
    name: v.object({
      first: v.string(),
      last: v.string(),
    }),
    email: v.string(),
  }),
});

const userForm = createForm({ schema: UserSchema });

// ✓ Valid paths - TypeScript provides autocompletion
// <Field of={userForm} path={['profile', 'name', 'first']} />
// <Field of={userForm} path={['profile', 'email']} />

// ✗ Invalid paths - TypeScript error
// <Field of={userForm} path={['profile', 'age']} />
// <Field of={userForm} path={['username']} />
```

## Type-safe props

To pass your form to another component via props, you can use the <Link href="/svelte/api/FormStore/">`FormStore`</Link> type along with your schema type to get full type safety.

```svelte
<script lang="ts">
  import { createForm, Form, type FormStore } from '@formisch/svelte';
  import * as v from 'valibot';

  const LoginSchema = v.object({
    email: v.pipe(v.string(), v.email()),
    password: v.pipe(v.string(), v.minLength(8)),
  });

  const loginForm = createForm({
    schema: LoginSchema,
  });
</script>

<FormContent of={loginForm} />

<!-- In another file -->
<script lang="ts">
  import {
    Form,
    type FormStore,
    type SubmitEventHandler,
  } from '@formisch/svelte';
  import * as v from 'valibot';

  const LoginSchema = v.object({
    email: v.pipe(v.string(), v.email()),
    password: v.pipe(v.string(), v.minLength(8)),
  });

  type FormContentProps = {
    of: FormStore<typeof LoginSchema>;
  };

  let { of } = $props<FormContentProps>();

  const handleSubmit: SubmitEventHandler<typeof LoginSchema> = (
    output,
    _event
  ) => console.log(output);
</script>

<Form of={of} onsubmit={handleSubmit}>
  <!-- Form fields -->
</Form>
```

## Generic field components

You can create generic field components with proper TypeScript typing using the <Link href="/svelte/api/FormStore/">`FormStore`</Link> type with Valibot's `GenericSchema`.

```svelte
<script lang="ts" generics="T extends v.GenericSchema<{ email: string }>">
  import { type FormStore, useField } from '@formisch/svelte';
  import * as v from 'valibot';

  type EmailInputProps = {
    of: FormStore<T>;
  };

  let { of } = $props<EmailInputProps>();

  const field = useField(of, { path: ['email'] });
</script>

<div>
  <label>
    Email
    <input {...field.props} value={field.input} type="email" />
  </label>
  {#if field.errors}
    <div>{field.errors[0]}</div>
  {/if}
</div>
```

The `v.GenericSchema<{ email: string }>` type ensures that the form passed to the component must have an `email` field of type `string`. TypeScript will catch any type mismatches at compile time.

## Available types

Most types you need can be imported from `@formisch/svelte`. You can find all available types in our <Link href="/svelte/api/">API reference</Link>.

- <Link href="/svelte/api/FormStore/">`FormStore`</Link> - The form store type
- <Link href="/svelte/api/FieldStore/">`FieldStore`</Link> - The field store
  type
- <Link href="/svelte/api/FieldArrayStore/">`FieldArrayStore`</Link> - The field
  array store type
- <Link href="/core/api/ValidPath/">`ValidPath`</Link> - Type for valid field
  paths
- <Link href="/core/api/ValidArrayPath/">`ValidArrayPath`</Link> - Type for
  valid array field paths
- <Link href="/core/api/Schema/">`Schema`</Link> - Base schema type from Valibot
- <Link href="/core/api/SubmitHandler/">`SubmitHandler`</Link> - Type for submit
  handlers without the event
- <Link href="/core/api/SubmitEventHandler/">`SubmitEventHandler`</Link> - Type
  for submit handlers with the event
