<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ formdata - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ formdata - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 23 Jun 2026 22:45:09 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/formdata/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Enforce Type Safety in FormData with TypeScript ]]>
                </title>
                <description>
                    <![CDATA[ When working with the FormData interface in JavaScript, where data is appended as key/value pairs, there's no built-in way to enforce type safety on the keys you append. This can lead to typos, missing keys, and unexpected runtime errors. But in Type... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-enforce-type-safety-in-formdata-with-typescript/</link>
                <guid isPermaLink="false">67cef1f13c2aba931eee9785</guid>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ formdata ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Olabisi Olaoye ]]>
                </dc:creator>
                <pubDate>Mon, 10 Mar 2025 14:06:41 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741615550682/6e709ad7-f8bb-4d26-acad-02f168d83acc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When working with the FormData interface in JavaScript, where data is appended as key/value pairs, there's no built-in way to enforce type safety on the keys you append. This can lead to typos, missing keys, and unexpected runtime errors. But in TypeScript, we can solve this by enforcing strict key validation.</p>
<p>I needed this solution myself when sending my form values to an API. I later realized that I had made several typographical errors in more than one key/value pair I was trying to append to my payload. Because FormData accepts any string as a key, I was able to pass in the wrong strings and proceed with the API request.</p>
<p>After this happened, I looked for a way to ensure that TypeScript doesn’t allow those errors.</p>
<p>This article will show you how to make <code>FormData</code> keys <strong>type-safe</strong> using TypeScript.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To get the most out of this article, you should have a basic understanding of the following:</p>
<ol>
<li><p>JavaScript programming</p>
</li>
<li><p>TypeScript fundamentals, especially how interfaces, types, and the <code>keyof</code> operator work</p>
</li>
<li><p>the FormData interface</p>
</li>
</ol>
<p>If you’re new to TypeScript or FormData, I recommend checking out <a target="_blank" href="https://www.typescriptlang.org/docs/">TypeScript’s official documentation</a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/FormData">MDN’s guide on FormData</a> before proceeding.</p>
<h2 id="heading-step-1-define-your-allowed-keys">Step 1: Define Your Allowed Keys</h2>
<h3 id="heading-the-old-way">The Old Way</h3>
<p>The default way of appending data with FormData is to do it manually, with plain strings:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> payload = <span class="hljs-keyword">new</span> FormData();

payload.append(<span class="hljs-string">"id"</span>, <span class="hljs-string">"1122"</span>);
payload.append(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Clark Kent"</span>);

payload.append(<span class="hljs-string">"agge"</span>, <span class="hljs-string">"36"</span>); <span class="hljs-comment">// Typo in key is allowed</span>
</code></pre>
<p>In the code snippet above, you can see that there was a typo when defining a key for <code>age</code>. But TypeScript won’t flag it as an error, and this could lead to errors when this data is sent with an API request.</p>
<h3 id="heading-the-better-way">The Better Way</h3>
<p>Instead of manually typing out the keys, define them in an object schema with a TypeScript interface.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> MyAllowedData {
    id: <span class="hljs-built_in">number</span>;
    name: <span class="hljs-built_in">string</span>;
    age: <span class="hljs-built_in">number</span>;
}
</code></pre>
<p>Alternatively, you can define them with types:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> MyAllowedData = {
    id: <span class="hljs-built_in">number</span>;
    name: <span class="hljs-built_in">string</span>;
    age: <span class="hljs-built_in">number</span>;
}
</code></pre>
<p>You can use either types or interfaces, it’s just a matter of preference. You can find out more about how they differ in this <a target="_blank" href="https://www.typescriptlang.org/play/?#example/types-vs-interfaces">official TypeScript documentation playground</a>.</p>
<p>Next, define a union type from each key in your interface.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> MyFormDataKeys = keyof MyAllowedData
<span class="hljs-comment">// this is the same as `type MyFormDataKeys = 'id' | 'name' | 'age'`</span>
</code></pre>
<p>The <code>keyof</code> operator helps to create a union type of an object type’s keys, so it comes in really handy if you don’t want to manually define a union type for a larger object with many keys.</p>
<h2 id="heading-step-2-create-an-append-helper-function">Step 2: Create an Append Helper Function</h2>
<p>Now that you’ve defined your strictly-typed keys, the next step is to create a helper function that ensures only valid keys are appended to FormData.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">appendToFormData</span> (<span class="hljs-params">formData: FormData, key: MyFormDataKeys, value: <span class="hljs-built_in">string</span></span>) </span>{
  formData.append(key, value);
};
</code></pre>
<p>The <code>appendToFormData</code> function takes in three arguments. Here’s how it all works:</p>
<ul>
<li><p>The first argument, <code>formData</code>, is an instance of the FormData object. This is where key/value pairs will be appended before sending them in an API request.</p>
</li>
<li><p>The second argument, <code>key</code>, is the key name of the field you want to append. Its type is of <code>MyFormDataKeys</code>, the union type we created to ensure only those keys we defined are appended to FormData.</p>
</li>
<li><p>The third argument is a string <code>value</code> which represents the value to be appended with the key.</p>
</li>
</ul>
<p>Note that <strong>FormData only accepts the</strong> <code>string</code> <strong>and</strong> <code>Blob</code> <strong>types as values</strong> in each key/value pair. In this guide, we’re only working with string values – but keep in mind that you can use blob values for appending files to API requests.</p>
<p>Now, let’s test out the function:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> payload = <span class="hljs-keyword">new</span> FormData();

appendToFormData(payload, <span class="hljs-string">"id"</span>, <span class="hljs-string">"19282"</span>); <span class="hljs-comment">// ✅ Allowed</span>
appendToFormData(payload, <span class="hljs-string">"name"</span>, <span class="hljs-string">"Lenny Brown"</span>); <span class="hljs-comment">// ✅ Allowed</span>
appendToFormData(payload, <span class="hljs-string">"age"</span>, <span class="hljs-string">"20"</span>); <span class="hljs-comment">// ✅ Allowed</span>

appendToFormData(payload, <span class="hljs-string">"someOtherKey"</span>, <span class="hljs-string">"89"</span>); <span class="hljs-comment">// ❌ TypeScript Error: Argument of type 'someOtherKey' is not assignable.</span>
</code></pre>
<h2 id="heading-step-3-use-the-helper-function-after-form-submission">Step 3: Use the Helper Function after Form Submission</h2>
<p>Now let’s append our fields to FormData before sending them to an API.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> handleSubmitForm = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> payload = <span class="hljs-keyword">new</span> FormData();
   appendToFormData(payload, <span class="hljs-string">"id"</span>, <span class="hljs-string">"19282"</span>);
   appendToFormData(payload, <span class="hljs-string">"name"</span>, <span class="hljs-string">"Lenny Brown"</span>);
   appendToFormData(payload, <span class="hljs-string">"age"</span>, <span class="hljs-string">"20"</span>);

  <span class="hljs-comment">// Send payload via API</span>
  fetch(<span class="hljs-string">"/api/submit"</span>, { method: <span class="hljs-string">"POST"</span>, body: payload });
};
</code></pre>
<h3 id="heading-appending-fields-from-an-object">Appending Fields from an Object</h3>
<p>Alternatively, if you already have your entire payload in an object, you can avoid appending each field one by one by implementing the function like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> handleSubmitForm = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// all your fields in an object</span>
  <span class="hljs-keyword">const</span> formValues: MyAllowedData = {
    id: <span class="hljs-number">1123</span>,
    name: <span class="hljs-string">'John Doe'</span>,
    age: <span class="hljs-number">56</span>
  }
  <span class="hljs-keyword">const</span> payload = <span class="hljs-keyword">new</span> FormData();

  <span class="hljs-built_in">Object</span>.entries(formValues).forEach(<span class="hljs-function">(<span class="hljs-params">[key, value]</span>) =&gt;</span> {
    appendToFormData(payload, key <span class="hljs-keyword">as</span> MyFormDataKeys, <span class="hljs-string">`<span class="hljs-subst">${value}</span>`</span>); <span class="hljs-comment">// use template literals to pass in value</span>
  });

  <span class="hljs-comment">// Send payload via API</span>
  fetch(<span class="hljs-string">"/api/submit"</span>, { method: <span class="hljs-string">"POST"</span>, body: payload });
};
</code></pre>
<p>In the snippet above, we’re using <code>Object.entries</code> to iterate over each key/value pair in an object so it can be appended to the FormData object. Note that the value in each pair, whether it’s a string or a number, is passed as a string using <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals">template literals</a> to prevent a TypeScript type mismatch from the <code>value</code> argument in our helper function.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By leveraging TypeScript’s <code>keyof</code> operator, we can make <code>FormData.append()</code> fully type-safe. This simple technique helps prevent key mismatches and makes your API requests more reliable.</p>
<p>Let me know your thoughts about the article, and feel free to make any suggestions you think could improve my solution.</p>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
