T
TanStack3mo ago
extended-salmon

What is the correct way to use `withForm` with additional props?

I have the following code:
export const Form = withForm({
...formOptions,
props: {} as {
tab: TabType;
onTabChange: (tab: TabType) => void;
onSubmit: (e: React.FormEvent) => void;
},
render: (props) => {
const { form, tab, onTabChange, onSubmit } = props;
return (
<form onSubmit={onSubmit} className="space-y-4">
{/* ... */}
</form>
);
},
});
export const Form = withForm({
...formOptions,
props: {} as {
tab: TabType;
onTabChange: (tab: TabType) => void;
onSubmit: (e: React.FormEvent) => void;
},
render: (props) => {
const { form, tab, onTabChange, onSubmit } = props;
return (
<form onSubmit={onSubmit} className="space-y-4">
{/* ... */}
</form>
);
},
});
The casting seems wrong, is there a better way to define additional props?
4 Replies
conscious-sapphire
conscious-sapphire3mo ago
you technically can extract it the same way as defaultValues:
interface FormProps {
tab: TabType;
onTabChange: (tab: TabType) => void;
onSubmit: (e: React.FormEvent) => void; // you could call this with `form.handleSubmit()` internally too, no?
}

const props: FormProps = {
tab: '',
onTabChange: () => {},
onSubmit: () => {}
}
interface FormProps {
tab: TabType;
onTabChange: (tab: TabType) => void;
onSubmit: (e: React.FormEvent) => void; // you could call this with `form.handleSubmit()` internally too, no?
}

const props: FormProps = {
tab: '',
onTabChange: () => {},
onSubmit: () => {}
}
however, these are never going to be runtime values, so you don't need to assign it actual values. This would be fine:
export const Form = withForm({
...formOptions,
props: {} as FormProps,
});
export const Form = withForm({
...formOptions,
props: {} as FormProps,
});
but it will throw a typescript error as interfaces are not indexable (and therefore not assignable to Records). Use a type instead:
type FormProps = {
tab: TabType;
onTabChange: (tab: TabType) => void;
onSubmit: (e: React.FormEvent) => void; // you could call this with `form.handleSubmit()` internally too, no?
}

export const Form = withForm({
...formOptions,
props: {} as FormProps,
});

// if you need to use an interface, you can convert one to a type like so:
type InterfaceAsType<T> = Omit<T, never>
type FormProps = {
tab: TabType;
onTabChange: (tab: TabType) => void;
onSubmit: (e: React.FormEvent) => void; // you could call this with `form.handleSubmit()` internally too, no?
}

export const Form = withForm({
...formOptions,
props: {} as FormProps,
});

// if you need to use an interface, you can convert one to a type like so:
type InterfaceAsType<T> = Omit<T, never>
extended-salmon
extended-salmonOP3mo ago
Gotcha, makes sense! I’m using types so the last option works great, just felt a bit weird And yeah could call form.onSubmit, this was mostly generated by AI so have to clean it up 😉
conscious-sapphire
conscious-sapphire3mo ago
understandable! The reason this assertion is required is because partial inheritance doesn't exist for typescript yet so you can't add one generic and infer the rest, it's either all or none also make sure to feed the markdown versions of guides to LLMs (add .md to the link) they may be out of date on TSF stuff
extended-salmon
extended-salmonOP3mo ago
Ahhhh yeah that makes sense, I was going to ask what it can’t be a generic parameter

Did you find this page helpful?