在JavaScript中使用FormData接口时,数据被追加为键/值对,但没有内置的方法来强制执行对追加的键进行类型安全验证。这可能导致拼写错误、缺少键和意外的运行时错误。但是在TypeScript中,我们可以通过强制执行严格的键验证来解决这个问题。
当我将表单值发送到API时,我自己也需要这个解决方案。后来我意识到,在我试图追加到负载中的多个键/值对中,我犯了几个拼写错误。因为FormData接受任何字符串作为键,所以我能够传入错误的字符串并继续进行API请求。
在此情况发生后,我寻找了一种方法来确保TypeScript不允许出现这些错误。
本文将向您展示如何使用TypeScript使FormData
的键类型安全。
先决条件
为了充分理解本文内容,您应该对以下内容有基本的了解:
-
JavaScript编程
-
TypeScript基础知识,特别是接口、类型以及
keyof
运算符的工作原理 -
FormData接口
如果你是 TypeScript 或者 FormData 的新手,我建议在继续之前查看TypeScript 的官方文档和MDN 上关于 FormData 的指南。
第一步:定义允许的键
老方法
使用 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:创建一个追加助手函数
现在您已经定义了严格类型的键,下一步是创建一个助手函数,确保只有有效的键被追加到FormData
。
function appendToFormData (formData: FormData, key: MyFormDataKeys, value: string) {
formData.append(key, value);
};
appendToFormData
函数接受三个参数。以下是它的工作原理:
-
第一个参数
formData
是FormData
对象的一个实例。这是在将它们发送到API请求之前追加键/值对的地方。 -
第二个参数
key
是您想要追加的字段的键名。它的类型是MyFormDataKeys
,我们创建的联合类型,以确保只有我们定义的那些键被追加到FormData
。 -
第三个参数是一个字符串
value
,表示要与键一起追加的值。
请注意,FormData只接受 string
和 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错误:无法分配'type'的参数。
第三步:在表单提交后使用助手函数
现在,让我们在将字段发送到API之前将它们附加到FormData中。
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
对象。请注意,每个键/值对中的值(无论是字符串还是数字)都被传递为字符串,使用模板文字来防止我们辅助函数中value
参数的TypeScript类型不匹配。
结论
通过利用TypeScript的keyof
运算符,我们可以使FormData.append()
完全类型安全。这种简单的技术有助于防止键不匹配,并使您的API请求更可靠。
请告诉我您对这篇文章的想法,也欢迎提出任何您认为可以改进我的解决方案的建议。
感谢阅读!
Source:
https://www.freecodecamp.org/news/how-to-enforce-type-safety-in-formdata-with-typescript/