svelte-forms-lib
svelte-forms-lib copied to clipboard
<Form {context}> produces type error with TypeScript
Summary
With TypeScript, I would like to both use the helper components and have the values passed to my onSubmit handler be typed. In order to do this, I have to call createForm (to get type inference) and pass the resulting context to the Form helper. But when I do this I get a type error saying that my FormState type "is not assignable to type 'FormState<Record<string, any>>".
Example
The following working code produces the error:
<script lang="ts">
import * as yup from 'yup';
import { createForm, Form, Field, ErrorMessage } from 'svelte-forms-lib';
const schema = yup.object().shape({
title: yup.string().required().min(4),
description: yup.string().required().min(10)
});
const context = createForm({
initialValues: {
title: '',
description: ''
},
validationSchema: schema,
onSubmit: (values) => {
alert(JSON.stringify(values));
}
});
</script>
<Form {context}> <!-- TYPE ERROR -->
<div>
<label for="title">Title</label>
<Field type="text" name="title" id="title" />
<ErrorMessage name="title" />
</div>
<div>
<label for="description">Description</label>
<Field type="textarea" name="description" />
<ErrorMessage name="description" />
</div>
<button type="submit">Submit</button>
</Form>
Here is the type error:
Type 'FormState<{ title: string; description: string; }>' is not assignable to type 'FormState<Record<string, any>>'.
Types of property 'updateField' are incompatible.
Type '(field: "title" | "description", value: any) => void' is not assignable to type '(field: string, value: any) => void'.
Types of parameters 'field' and 'field' are incompatible.
Type 'string' is not assignable to type '"title" | "description"'.
Workaround
I am using the following workaround for now, declaring the context to have type 'any':
const context: any = createForm({ ... });
Possible fixes
I suspect that changing Record<string, any> to {[key: string]: any} in index.d.ts might correct the problem.
I think you are mixing two different ways of creating the form.
When you use the Form component you just have to provide the configuration that you now put into createForm. You don't have to use createForm itself.
When you just use a plain HTML <form/> element, then you use createForm.
Okay, thanks. I can make the type errors go away by doing that, but it makes too many type errors go away. Notice that I do not get a type error in the following code because the types of the initialValues properties are not inferred:

Notice that when I use createForm() the types of the initialValues properties are inferred:

Besides, the type declaration indicates that the form context is supposed to be a valid input to the Form component, and providing the form context as input actually works (aside from the type error):
export type FormProps<Inf = Record<string, unknown>> = {
context?: FormState;
initialValues?: Inf;
onSubmit?: ((values: Inf) => any) | ((values: Inf) => Promise<any>);
validate?: (values: Inf) => any | undefined;
validationSchema?: ObjectSchema<any>;
} & svelte.JSX.HTMLAttributes<HTMLFormElement>;
/* ... */
declare class Form extends SvelteComponentTyped<
FormProps,
Record<string, unknown>,
{
default: FormState;
}
> {}
I forked the repo to experiment with a possible solution, but I get this error that I can't figure out how to resolve:
Cannot find lib definition for 'svelte2tsx'.ts(2726)

The TypeScript docs indicate that /// <reference lib="some-lib-name" /> is for referencing "built-in" libraries.
Any update on this issue?