Новый хук useActionState в React 19 позволяет обрабатывать отправку данных в формах, пример:
export default function Page() {
const [_, action, pending] = useActionState((_: unknown, formData: FormData) => {
const firstName = formData.get("firstName");
const age = formData.get("age");
}, null);
return (
<form action={action}>
<input type="text" name="firstName" />
<input type="number" name="age" />
<button type="submit" disabled={pending}>Submit</button>
</form>
);
}
При отправке формы в колбек хука приходит объект типа FormData. В примере formData.get может принимать любой string и нет уверенности что этот string совпадает с именем поля на форме. Для решения этой проблемы, автор предлагает создать компонент поля, которое принимает дженерик с названиями полей и создать функцию получения значения из FormData, которое также принимает дженерик. Пример:
type FormName = "firstName" | "age";
const get = <Name extends string = never>(
formData: FormData,
name: NoInfer<Name>
) => formData.get(name);
export default function Page() {
const [_, action] = useActionState((_: unknown, formData: FormData) => {
const firstName = get<FormName>(formData, "firstName");
const age = get<FormName>(formData, "age");
}, null);
return (
<form action={action}>
<SaveInput<FormName> type="text" name="firstName" />
<SaveInput<FormName> type="number" name="age" />
<button type="submit">Submit</button>
</form>
);
}
Теперь тип FormName связывает поля на форме и FormData, так что больше нет риска опечаток.
https://www.typeonce.dev/article/make-form-data-and-input-names-type-safe-in-react