Когда вы работаете с интерфейсом FormData в JavaScript, где данные добавляются в виде пар ключ/значение, нет встроенного способа обеспечить безопасность типов для ключей, которые вы добавляете. Это может привести к опечаткам, отсутствующим ключам и неожиданным ошибкам во время выполнения. Но в TypeScript мы можем решить эту проблему, обеспечивая строгую проверку ключей.
Мне самому понадобилось это решение, когда я отправлял значения формы в API. Позже я осознал, что допустил несколько опечаток в более чем одной паре ключ/значение, которые я пытался добавить к своей нагрузке. Поскольку FormData принимает любую строку в качестве ключа, я смог передать неправильные строки и продолжить запрос к API.
После этого я искал способ гарантировать, что TypeScript не позволит этих ошибок.
В этой статье я покажу вам, как сделать FormData
ключи безопасными по типу с помощью TypeScript.
Предварительные требования
Чтобы извлечь максимальную пользу из этой статьи, вы должны иметь базовое понимание следующего:
-
Программирование на JavaScript
-
Основы TypeScript, особенно как работают интерфейсы, типы и оператор
keyof
-
интерфейс FormData
Если вы новичок в TypeScript или FormData, я рекомендую сначала ознакомиться с официальной документацией TypeScript и руководством MDN по FormData, прежде чем продолжать.
Шаг 1: Определите допустимые ключи
Старый способ
Обычно данные добавляются в FormData вручную, с использованием простых строк:
const payload = new FormData();
payload.append("id", "1122");
payload.append("name", "Clark Kent");
payload.append("agge", "36"); // Опечатка в ключе допустима
В приведенном выше фрагменте кода видно, что была опечатка при определении ключа для age
. Но TypeScript не отметит это как ошибку, и это может привести к ошибкам при отправке этих данных с API-запросом.
Лучший способ
Вместо того чтобы вручную вводить ключи, определите их в схеме объекта с помощью интерфейса TypeScript.
interface MyAllowedData {
id: number;
name: string;
age: number;
}
В качестве альтернативы вы можете определить их с помощью типов:
type MyAllowedData = {
id: number;
name: string;
age: number;
}
Вы можете использовать либо типы, либо интерфейсы, это просто вопрос предпочтений. Вы можете узнать больше о том, чем они отличаются, в этом официальном игровом поле документации TypeScript.
Далее определите объединяющий тип из каждого ключа в вашем интерфейсе.
type MyFormDataKeys = keyof MyAllowedData
// это то же самое, что `type MyFormDataKeys = 'id' | 'name' | 'age'`
Оператор keyof
помогает создать объединенный тип ключей типа объекта, поэтому он действительно удобен, если вы не хотите вручную определять объединенный тип для большого объекта с множеством ключей.
Шаг 2: Создание вспомогательной функции Append
Теперь, когда вы определили ваши строго типизированные ключи, следующим шагом будет создание вспомогательной функции, которая гарантирует, что к форме FormData добавляются только допустимые ключи.
function appendToFormData (formData: FormData, key: MyFormDataKeys, value: string) {
formData.append(key, value);
};
Функция appendToFormData
принимает три аргумента. Вот как это все работает:
-
Первый аргумент,
formData
, является экземпляром объекта FormData. Здесь будут добавляться пары ключ/значение перед отправкой их в запрос API. -
Второй аргумент,
key
, это имя ключа поля, которое вы хотите добавить. Его тип –MyFormDataKeys
, объединенный тип, который мы создали, чтобы гарантировать, что к FormData добавляются только те ключи, которые мы определили. -
Третий аргумент – строка
value
, которая представляет собой значение, которое должно быть добавлено с ключом.
Обратите внимание, что FormData принимает только строки
и Blob
типы в качестве значений в каждой паре ключ/значение. В этом руководстве мы работаем только со строковыми значениями – но имейте в виду, что вы можете использовать значения blob для добавления файлов в запросы к API.
Теперь давайте протестируем функцию:
const payload = new FormData();
appendToFormData(payload, "id", "19282"); // ✅ Разрешено
appendToFormData(payload, "name", "Lenny Brown"); // ✅ Разрешено
appendToFormData(payload, "age", "20"); // ✅ Разрешено
appendToFormData(payload, "someOtherKey", "89"); // ❌ Ошибка TypeScript: Аргумент типа 'someOtherKey' не может быть присвоен.
Шаг 3: Используйте вспомогательную функцию после отправки формы
Теперь давайте добавим наши поля в FormData перед отправкой их на API.
const handleSubmitForm = () => {
const payload = new FormData();
appendToFormData(payload, "id", "19282");
appendToFormData(payload, "name", "Lenny Brown");
appendToFormData(payload, "age", "20");
// Отправить нагрузку через API
fetch("/api/submit", { method: "POST", body: payload });
};
Добавление полей из объекта
В качестве альтернативы, если у вас уже есть вся нагрузка в объекте, вы можете избежать добавления каждого поля по отдельности, реализовав функцию следующим образом:
const handleSubmitForm = () => {
// все ваши поля в объекте
const formValues: MyAllowedData = {
id: 1123,
name: 'John Doe',
age: 56
}
const payload = new FormData();
Object.entries(formValues).forEach(([key, value]) => {
appendToFormData(payload, key as MyFormDataKeys, `${value}`); // используйте шаблонные литералы для передачи значения
});
// Отправить нагрузку через API
fetch("/api/submit", { method: "POST", body: payload });
};
В приведенном фрагменте мы используем Object.entries
, чтобы перебрать каждую пару ключ/значение в объекте, чтобы добавить их в объект FormData. Обратите внимание, что значение в каждой паре, будь то строка или число, передается как строка, используя шаблонные литералы, чтобы предотвратить несоответствие типов TypeScript из-за аргумента value
в нашей вспомогательной функции.
Заключение
Используя оператор keyof
TypeScript, мы можем сделать FormData.append()
полностью безопасным с точки зрения типов. Эта простая техника помогает предотвратить несоответствия ключей и делает ваши API-запросы более надежными.
Сообщите мне ваше мнение о статье и не стесняйтесь вносить предложения, которые, по вашему мнению, могут улучшить мое решение.
Спасибо за чтение!
Source:
https://www.freecodecamp.org/news/how-to-enforce-type-safety-in-formdata-with-typescript/