@shpaw415/formdata-parser
v0.1.1
Published
A simple library to parse FormData objects into plain JavaScript objects.
Readme
formdata-parser
Parse FormData / URLSearchParams into a typed JavaScript object using inline field prefixes like:
number::age=22array::tags=a,b,cboolean::pro=truejson::meta={"a":1}
✅ Works in Node, Bun, Deno, Browsers, Edge
✅ Type casting + nested keys + multi-values
✅ Zero dependencies
Installation
npm install @shpaw415/formdata-parseror
bun add @shpaw415/formdata-parserQuick Example (HTML)
This works directly in the browser:
<form id="my-form">
<input name="string::name" value="John" />
<input name="number::age" value="22" />
<input name="boolean::pro" value="true" />
<input name="array::tags" value="js, ts, bun" />
<input name="json::meta" value='{"role":"admin"}' />
<button type="submit">Submit</button>
</form>
<script type="module">
import { parseTypedFormData } from "typed-formdata";
const form = document.querySelector("#my-form");
form.addEventListener("submit", (e) => {
e.preventDefault();
const fd = new FormData(form);
const obj = parseTypedFormData(fd);
console.log(obj);
});
</script>Output:
{
"name": "John",
"age": 22,
"pro": true,
"tags": ["js", "ts", "bun"],
"meta": { "role": "admin" }
}Why?
FormData always returns strings.
So instead of manually writing this everywhere:
const age = Number(fd.get("age"));
const tags = String(fd.get("tags")).split(",");You can just send:
number::age=22
array::tags=a,b,cAnd the parser automatically returns:
{ "age": 22, "tags": ["a", "b", "c"] }Supported Types
| Prefix | Example input | Output |
| ----------- | -------------------------- | --------------- |
| string:: | string::name=Justin | "Justin" |
| number:: | number::age=22 | 22 |
| boolean:: | boolean::pro=true | true |
| array:: | array::tags=a,b,c | ["a","b","c"] |
| json:: | json::meta={"a":1} | { a: 1 } |
| date:: | date::startAt=2026-01-01 | Date |
Array separators
By default, array:: uses a comma.
fd.set("array::tags", "a,b,c");Output:
{
tags: ["a", "b", "c"];
}Custom separator
Use:
array(|)::tags=a|b|cExample:
fd.set("array(|)::tags", "admin|dev|owner");Output:
{
tags: ["admin", "dev", "owner"];
}Multi-value fields (append)
If your form sends the same field multiple times:
fd.append("array::tags", "a,b");
fd.append("array::tags", "c,d");Output:
{
tags: ["a", "b", "c", "d"];
}List key/value pairs
Build dynamic dictionaries by pairing list::key and list::value inputs that share the same name and index:
fd.set("list::key::env::0", "API_URL");
fd.set("list::value::env::0", "https://example.com");
fd.set("list::key::env::1", "API_TOKEN");
fd.set("list::value::env::1", "secret");Output:
{
env: {
API_URL: "https://example.com",
API_TOKEN: "secret"
}
}Keys with empty values are skipped automatically.
Nested keys
Dots create nested objects:
fd.set("user.name", "John");
fd.set("number::user.age", "30");Output:
{
user: {
name: "John",
age: 30
}
}Files support
If a FormData entry is a File, it is kept as-is:
fd.set("file::avatar", myFile);Output:
{
avatar: File(...)
}Note:
file::is optional. AnyFilewill be returned as aFile.
API
parseTypedFormData(input, options?)
Input
Supports:
FormDataURLSearchParams- plain objects (
Record<string, any>)
Options
type ParseOptions = {
ignoreEmpty?: boolean;
strict?: boolean;
defaultArraySeparator?: string;
};ignoreEmpty
If enabled, empty strings are ignored:
parseTypedFormData(fd, { ignoreEmpty: true });strict
If enabled, invalid casts throw:
- invalid number
- invalid JSON
- invalid date
- invalid boolean
parseTypedFormData(fd, { strict: true });defaultArraySeparator
Change the default separator for array:::
parseTypedFormData(fd, { defaultArraySeparator: ";" });Boolean parsing rules
Accepted values:
true
true1yeson
false
false0nooff
TypeScript
This package is written in TypeScript and ships with types.
License
MIT
