formdata
js/globals/formdata.ts
FormData global (WHATWG XHR / Fetch spec).
Learn more:
- XMLHttpRequest FormData: https://xhr.spec.whatwg.org/#interface-formdata
- Fetch body handling: https://fetch.spec.whatwg.org/
FormData is the standard representation of an HTML form submission. It
holds an ordered list of name/value entries where values are either strings
or File objects (Blobs with a filename). It is used as a request body in
the Fetch API and as the basis for multipart/form-data serialization.
This release supports outgoing multipart/form-data serialization only;
parsing incoming multipart request bodies into FormData is intentionally
outside the release scope.
Fino also supports new FormData(existingFormData) as a nonstandard
convenience extension for shallow-copying entries. Browser constructors
accept an HTML form element instead.
Entry normalization (_normalizeEntry)
The WHATWG spec requires that values be normalized on insertion:
- String values are coerced via
String(value). Simple. - Blob values are wrapped in a
Fileobject. If the caller provides afilenameargument it is used; otherwise the filename defaults to"blob"(per spec), unless the value is already aFile, in which case itsfile.nameis used as the default. This ensures that every Blob entry in the FormData has a filename, which is required for multipart encoding.
The wrapping-in-File step is non-obvious: even if the value is already a
File, it gets re-wrapped into a new File if a filename argument is
explicitly provided. This matches the spec and allows callers to override
the filename at append time.
Entry ordering and duplicates
FormData is an ordered list, not a map. Multiple entries can share the same
name. get() returns only the first match; getAll() returns all matches.
set() replaces the first match and removes all subsequent ones, preserving
the position of the first occurrence. delete() removes all entries with
the given name.
Iteration
The [Symbol.iterator]() method delegates to entries(), so FormData
instances can be iterated with for...of to get [key, value] pairs,
matching the browser API. Iterators are live and read from the current entry
list as they advance, so entries appended before completion can be observed
and entries deleted before their turn are skipped.
// FormData is available via globalThis
const fd = new FormData();
fd.append('name', 'Alice');
fd.append('avatar', blob, 'avatar.png');
fd.get('name'); // 'Alice'
fd.getAll('name'); // ['Alice']
fd.has('name'); // true
fd.set('name', 'Bob');
fd.delete('name');
for (const [key, value] of fd) { ... }
fd.forEach((value, key, fd) => { ... });
Types
type FormDataEntryValue = string | File
Value stored in a FormData entry.
String entries represent regular form fields. File entries represent Blob values after FormData normalizes them with a filename for multipart/form-data serialization.
Classes
class FormData {
Ordered collection of string and File form entries.
Duplicate names are allowed and insertion order is preserved. Blob values are normalized into File entries so multipart serialization always has a filename.
const form = new FormData();
form.append('name', 'Alice');
form.get('name'); // "Alice"
Constructors
constructor(init?: FormData)
Create an empty FormData or shallow-copy an existing FormData.
The copy-constructor form is a nonstandard Fino extension. It preserves entry order and does not deep-clone File objects.
const source = new FormData();
source.append('x', '1');
const copy = new FormData(source);
Methods
append(name: string, value: string | Blob, filename?: string): void
Append a new entry without removing existing entries with the same name.
Names and string values are string-coerced and line endings are normalized to CRLF. Blob values become File values: the filename argument sets the name, otherwise a plain Blob defaults to "blob" and an existing File keeps its own name.
const form = new FormData();
form.append('tag', 'a');
form.append('tag', 'b');
form.getAll('tag'); // ["a", "b"]
delete(name: string): void
Remove every entry with the given name.
Unknown names are ignored. The name is string-coerced before matching.
const form = new FormData();
form.append('x', '1');
form.delete('x');
form.has('x'); // false
get(name: string): FormDataEntryValue | null
Return the first value for a name, or null when absent.
File entries are returned as File instances. Duplicate entries after the first are ignored by this method.
const form = new FormData();
form.append('x', '1');
form.get('x'); // "1"
getAll(name: string): FormDataEntryValue[]
Return all values for a name in insertion order.
The returned array is new, so mutating it does not affect the FormData.
const form = new FormData();
form.append('x', '1');
form.append('x', '2');
form.getAll('x'); // ["1", "2"]
has(name: string): boolean
Return true when at least one entry exists for name.
const form = new FormData();
form.append('x', '1');
form.has('x'); // true
set(name: string, value: string | Blob, filename?: string): void
Replace entries for a name with a single normalized entry.
The first matching position is preserved and later duplicates are removed. If the name did not exist, the new entry is appended.
const form = new FormData();
form.append('x', '1');
form.set('x', '2');
form.getAll('x'); // ["2"]
*entries(): IterableIterator<[string, FormDataEntryValue]>
Iterate over [name, value pairs in insertion order.
The iterator is live and reads the current entry list as it advances.
const form = new FormData();
form.append('x', '1');
[...form.entries()]; // [["x", "1"]]
*keys(): IterableIterator<string>
Iterate over entry names in insertion order.
Duplicate names appear once for each entry.
const form = new FormData();
form.append('x', '1');
[...form.keys()]; // ["x"]
*values(): IterableIterator<FormDataEntryValue>
Iterate over values in insertion order.
Values are strings or File objects.
const form = new FormData();
form.append('x', '1');
[...form.values()]; // ["1"]
forEach(
callback: (
value: FormDataEntryValue,
name: string,
parent: FormData
) => void,
thisArg?: unknown
): void
Call a callback for each entry in insertion order.
The callback receives value, name, and the FormData object. thisArg is used as the callback receiver when provided.
const form = new FormData();
form.append('x', '1');
form.forEach((value, name) => console.log(name, value));