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

```tsx
import { Field, Form, useForm$ } from '@formisch/qwik';
import { component$ } from '@qwik.dev/core';
import * as v from 'valibot';

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

export default component$(() => {
  const loginForm = useForm$(() => ({
    schema: LoginSchema,
  }));

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

  return (
    <Form
      of={loginForm}
      onSubmit$={(output, event) => {
        // output is fully typed based on LoginSchema
        console.log(output.email); // ✓ Type-safe
        console.log(output.username); // ✗ TypeScript error
      }}
    >
      {/* 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.

```tsx
import { Field, Form, useForm$ } from '@formisch/qwik';
import { component$ } from '@qwik.dev/core';
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()
  ),
});

export default component$(() => {
  const profileForm = useForm$(() => ({
    schema: ProfileSchema,
  }));

  return (
    <Form
      of={profileForm}
      onSubmit$={(output, event) => {
        // output is: { age: number; birthDate: Date }
        console.log(output.age); // number
        console.log(output.birthDate); // Date
      }}
    >
      <Field
        of={profileForm}
        path={['age']}
        render$={(field) => (
          // field.input is a signal containing string
          <input {...field.props} value={field.input.value} type="text" />
        )}
      />

      <Field
        of={profileForm}
        path={['birthDate']}
        render$={(field) => (
          // field.input is a signal containing string
          <input {...field.props} value={field.input.value} type="date" />
        )}
      />

      <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.

```tsx
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']} render$={(field) => ...} />
<Field of={userForm} path={['profile', 'email']} render$={(field) => ...} />

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

## Type-safe props

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

```tsx
import { Form, type FormStore, useForm$ } from '@formisch/qwik';
import { component$ } from '@qwik.dev/core';
import * as v from 'valibot';

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

export default component$(() => {
  const loginForm = useForm$(() => ({
    schema: LoginSchema,
  }));

  return <FormContent of={loginForm} />;
});

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

export const FormContent = component$<FormContentProps>((props) => {
  return (
    <Form of={props.of} onSubmit$={(output, event) => console.log(output)}>
      {/* Form fields */}
    </Form>
  );
});
```

## Generic field components

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

```tsx
import { type FormStore, useField$ } from '@formisch/qwik';
import { component$ } from '@qwik.dev/core';
import * as v from 'valibot';

type EmailInputProps = {
  of: FormStore<v.GenericSchema<{ email: string }>>;
};

export const EmailInput = component$<EmailInputProps>((props) => {
  const field = useField$(props.of, { path: ['email'] });

  return (
    <div>
      <label>
        Email
        <input {...field.props} value={field.input.value} type="email" />
      </label>
      {field.errors.value && <div>{field.errors.value[0]}</div>}
    </div>
  );
});
```

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/qwik`. You can find all available types in our <Link href="/qwik/api/">API reference</Link>.

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