# 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="/vue/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.

```vue
<script setup lang="ts">
import { Field, Form, useForm } from '@formisch/vue';
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 = useForm({
  schema: LoginSchema,
});

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

<template>
  <Form
    :of="loginForm"
    @submit="
      (output) => {
        // output is fully typed based on LoginSchema
        console.log(output.email); // ✓ Type-safe
        console.log(output.username); // ✗ TypeScript error
      }
    "
  >
    <!-- Form fields -->
  </Form>
</template>
```

### Input and output types

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

```vue
<script setup lang="ts">
import { Field, Form, useForm } from '@formisch/vue';
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 = useForm({
  schema: ProfileSchema,
});
</script>

<template>
  <Form
    :of="profileForm"
    @submit="
      (output) => {
        // output is: { age: number; birthDate: Date }
        console.log(output.age); // number
        console.log(output.birthDate); // Date
      }
    "
  >
    <Field :of="profileForm" :path="['age']" v-slot="field">
      <!-- field.input is string -->
      <input v-bind="field.props" v-model="field.input" type="text" />
    </Field>

    <Field :of="profileForm" :path="['birthDate']" v-slot="field">
      <!-- field.input is string -->
      <input v-bind="field.props" v-model="field.input" type="date" />
    </Field>

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

### 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 = useForm({ schema: UserSchema });

// ✓ Valid paths - TypeScript provides autocompletion
<Field :of="userForm" :path="['profile', 'name', 'first']" v-slot="field" />
<Field :of="userForm" :path="['profile', 'email']" v-slot="field" />

// ✗ Invalid paths - TypeScript error
<Field :of="userForm" :path="['profile', 'age']" v-slot="field" />
<Field :of="userForm" :path="['username']" v-slot="field" />
```

## Type-safe props

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

```vue
<script setup lang="ts">
import { Form, type FormStore, useForm } from '@formisch/vue';
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 = useForm({
  schema: LoginSchema,
});
</script>

<template>
  <FormContent :of="loginForm" />
</template>

<script setup lang="ts">
type FormContentProps = {
  of: FormStore<typeof LoginSchema>;
};

defineProps<FormContentProps>();
</script>

<template>
  <Form :of="props.of" @submit="(output, event) => console.log(output)">
    <!-- Form fields -->
  </Form>
</template>
```

## Generic field components

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

```vue
<script
  setup
  lang="ts"
  generic="TSchema extends v.GenericSchema<{ email: string }>"
>
import { useField } from '@formisch/vue';
import type { FormStore } from '@formisch/vue';
import * as v from 'valibot';

export interface EmailInputProps<
  TSchema extends v.GenericSchema<{ email: string }>,
> {
  of: FormStore<TSchema>;
}

const props = defineProps<EmailInputProps<TSchema>>();

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

<template>
  <div>
    <label>
      Email
      <input v-bind="field.props" v-model="field.input" type="email" />
    </label>
    <div v-if="field.errors">{{ field.errors[0] }}</div>
  </div>
</template>
```

The `v.GenericSchema<{ email: string }>` type ensures that the form passed to `EmailInput` 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/vue`. You can find all available types in our <Link href="/vue/api/">API reference</Link>.

- <Link href="/vue/api/FormStore/">`FormStore`</Link> - The form store type
- <Link href="/vue/api/FieldStore/">`FieldStore`</Link> - The field store type
- <Link href="/vue/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
