# 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="/solid/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 { createForm, Field, Form } from '@formisch/solid';
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 function LoginPage() {
  const loginForm = createForm({
    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 { createForm, Field, Form } from '@formisch/solid';
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 function ProfilePage() {
  const profileForm = createForm({
    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']}>
        {(field) => (
          // field.input is string
          <input {...field.props} value={field.input ?? ''} type="text" />
        )}
      </Field>

      <Field of={profileForm} path={['birthDate']}>
        {(field) => (
          // field.input is string
          <input {...field.props} value={field.input ?? ''} type="date" />
        )}
      </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.

```tsx
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="/solid/api/FormStore/">`FormStore`</Link> type along with your schema type to get full type safety.

```tsx
import { createForm, Form, type FormStore } from '@formisch/solid';
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 function LoginPage() {
  const loginForm = createForm({
    schema: LoginSchema,
  });

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

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

function FormContent(props: FormContentProps) {
  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="/solid/api/FormStore/">`FormStore`</Link> type with Valibot's `GenericSchema`.

```tsx
import { type FormStore, useField } from '@formisch/solid';
import type { Component } from 'solid-js';
import * as v from 'valibot';

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

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

  return (
    <div>
      <label>
        Email
        <input {...field.props} value={field.input ?? ''} type="email" />
      </label>
      {field.errors && <div>{field.errors[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/solid`. You can find all available types in our <Link href="/solid/api/">API reference</Link>.

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