Last active
September 7, 2022 20:37
-
-
Save joemaffei/e5e5079a739e398d00d489349b8e39f2 to your computer and use it in GitHub Desktop.
Convert object to FormData
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* I started building this, then came across a more robust solution: | |
* {@link https://github.com/therealparmesh/object-to-formdata} | |
*/ | |
import { isPlainObject } from "is-plain-object"; | |
type Value = string | Blob | number | boolean | null | undefined | Date; | |
function convert<T extends Value>(value: T): string | Blob { | |
if (typeof value === "string" || value instanceof Blob) { | |
return value; | |
} | |
if (typeof value === "number" || typeof value === "boolean") { | |
return value.toString(); | |
} | |
if (value instanceof Date) { | |
return value.toISOString(); | |
} | |
return ""; | |
} | |
export function buildFormData<T1>(input: T1) { | |
const formData = new FormData(); | |
(function serialize<T2>(obj: T2, root?: string) { | |
for (const key in obj) { | |
const path = root | |
? Array.isArray(obj) | |
? `${root}[${key}]` | |
: `${root}.${key}` | |
: key; | |
if (Array.isArray(obj[key]) || isPlainObject(obj[key])) { | |
serialize(obj[key], path); | |
} else { | |
formData.append(path, convert(obj[key] as Value)); | |
} | |
} | |
})(input); | |
return formData; | |
} | |
describe("helpers/formData", () => { | |
it("returns a FormData object", () => { | |
expect(buildFormData()).toBeInstanceOf(FormData); | |
}); | |
it("works with strings", () => { | |
const formData = buildFormData({ first: "1st", second: "2nd" }); | |
expect(formData.get("first")).toBe("1st"); | |
expect(formData.get("second")).toBe("2nd"); | |
}); | |
it("works with blobs", () => { | |
const formData = buildFormData({ blob: new Blob() }); | |
expect(formData.get("blob")).toBeInstanceOf(Blob); | |
}); | |
it("stringifies numbers", () => { | |
const formData = buildFormData({ first: 1, second: 2 }); | |
expect(formData.get("first")).toBe("1"); | |
expect(formData.get("second")).toBe("2"); | |
}); | |
it("stringifies booleans", () => { | |
const formData = buildFormData({ first: true, second: false }); | |
expect(formData.get("first")).toBe("true"); | |
expect(formData.get("second")).toBe("false"); | |
}); | |
it("converts null and undefined to empty strings", () => { | |
const formData = buildFormData({ first: null, second: undefined }); | |
expect(formData.get("first")).toBe(""); | |
expect(formData.get("second")).toBe(""); | |
}); | |
it("converts dates to ISO strings", () => { | |
const dateString = "2000-01-01T00:00:00.000Z"; | |
const date = new Date(dateString); | |
const formData = buildFormData({ date }); | |
expect(formData.get("date")).toBe(dateString); | |
}); | |
it("works on arrays of primitives", () => { | |
const formData = buildFormData({ arr: [1, 2] }); | |
expect(formData.get("arr[0]")).toBe("1"); | |
expect(formData.get("arr[1]")).toBe("2"); | |
}); | |
it("works on nested objects", () => { | |
const formData = buildFormData({ first: { a: 1 }, second: { b: 2 } }); | |
expect(formData.get("first.a")).toBe("1"); | |
expect(formData.get("second.b")).toBe("2"); | |
}); | |
it("works on arrays of objects", () => { | |
const formData = buildFormData({ | |
arr: [ | |
{ a: 1, b: 2 }, | |
{ c: 3, d: 4 }, | |
], | |
}); | |
expect(formData.get("arr[0].a")).toBe("1"); | |
expect(formData.get("arr[0].b")).toBe("2"); | |
expect(formData.get("arr[1].c")).toBe("3"); | |
expect(formData.get("arr[1].d")).toBe("4"); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment