在 JavaScript 中使用 FormData 接口時,數據被附加為鍵/值對,沒有內建的方法來強制鍵的類型安全性。這可能導致錯誤、遺漏的鍵和意外的運行時錯誤。但在 TypeScript 中,我們可以通過強制嚴格的鍵驗證來解決這個問題。
當我將表單值發送到 API 時,我自己就需要這個解決方案。後來我意識到,我在嘗試附加到載荷的多個鍵/值對中犯了幾個打字錯誤。因為 FormData 接受任何字符串作為鍵,所以我能夠傳入錯誤的字符串並繼續進行 API 請求。
這種情況發生後,我尋找了一種方法來確保 TypeScript 不允許這些錯誤。
本文將向您展示如何使用 TypeScript 使 FormData
的鍵 具有類型安全性。
先決條件
為了從本文中獲取最大收益,您應該對以下基本概念有基本的了解:
-
JavaScript 編程
-
TypeScript 基本原理,特別是介面、類型和
keyof
運算符的工作原理 -
FormData 接口
如果您是 TypeScript 或 FormData 的新手,我建議在繼續之前查閱TypeScript 的官方文檔和FormData 的 MDN 指南。
第一步:定義您允許的鍵
舊方法
使用 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錯誤:類型 'someOtherKey' 的參數不可分配。
步驟3:在表單提交後使用輔助函數
現在讓我們在將它們發送到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/