在 JavaScript 中使用 FormData 接口時,數據被附加為鍵/值對,沒有內建的方法來強制鍵的類型安全性。這可能導致錯誤、遺漏的鍵和意外的運行時錯誤。但在 TypeScript 中,我們可以通過強制嚴格的鍵驗證來解決這個問題。

當我將表單值發送到 API 時,我自己就需要這個解決方案。後來我意識到,我在嘗試附加到載荷的多個鍵/值對中犯了幾個打字錯誤。因為 FormData 接受任何字符串作為鍵,所以我能夠傳入錯誤的字符串並繼續進行 API 請求。

這種情況發生後,我尋找了一種方法來確保 TypeScript 不允許這些錯誤。

本文將向您展示如何使用 TypeScript 使 FormData 的鍵 具有類型安全性

先決條件

為了從本文中獲取最大收益,您應該對以下基本概念有基本的了解:

  1. JavaScript 編程

  2. TypeScript 基本原理,特別是介面、類型和 keyof 運算符的工作原理

  3. 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僅接受stringBlob類型作為每個鍵/值對的值。在本指南中,我們只處理字符串值 – 但請記住,您可以使用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請求更可靠。

讓我知道您對文章的想法,並隨時提出任何您認為可以改進我的解決方案的建議。

感謝您的閱讀!