Created
August 20, 2020 20:14
-
-
Save kangabru/5d6f1b2a10bcbd82fc20bad45dad59a0 to your computer and use it in GitHub Desktop.
Adds expected value types 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
// Before: untyped 😥 | |
const form1 = new FormData() | |
form1.get('url') // Is 'url' expected? | |
form1.append('image', '?') // Do I pass in a string or blob? | |
// After: same functionality but with types 😁 | |
const form2 = TypedFormData<{ title: string, image: Blob }>() | |
form2.get('url') // Throws error | |
form2.set('title', "Hello Github!") | |
form2.append('image', {} as Blob) // Error if string is used | |
/** Return a standard FormFata object but wrapped with expected types */ | |
function TypedFormData<T extends FormDataKeys<T>>(): TypedFormData<T> { | |
return new FormData() as any as TypedFormData<T> | |
} | |
/** Only allow properties with 'string' or 'blob' types. | |
* | |
* @howitworks | |
* What is it doing? | |
* Defines an object in the form: | |
* { [key]: key type } | |
* | |
* [K in keyof T] | |
* - Pulls out keys 'K' from type 'T' | |
* - example: T = { key1: string, key2: number } | |
* - result: K = 'key1' | 'key2' | |
* | |
* T[K] | |
* - Returns the type for the given key | |
* - example: T = { key1: string, key2: number } | |
* - result: T['key2'] -> number | |
* | |
* ValType extends string | Blob ? ValType : never; | |
* - Throw error if ValType isn't a string or blob | |
* - 'never' means the type isn't possible which throws the error | |
* */ | |
export type FormDataKeys<T> = { | |
[K in keyof T]: T[K] extends string | Blob ? T[K] : never; | |
} | |
/** Overwrite FormData 'get', 'set, and 'append' function with expected types. | |
* | |
* @howitworks | |
* What is it doing? | |
* Overrides FormData type with custom 'get', 'set', and 'append' functions | |
* | |
* Omit<FormData, 'get' | 'set' | 'append'> | |
* - Returns FormData type without 'get', 'set', and 'append' properties | |
* | |
* get: (key: keyof T) => T[typeof key] | |
* - Defines a 'get' function | |
* - Only permits calls with keys from T | |
* - Returns the correct value for the given key | |
* - Example: | |
* T = { key1: string, key2: number } | |
* get('key1') -> string | |
* get('key2') -> number | |
* get('key3') // error | |
* | |
* set: <K extends keyof T>(key: K, value: T[K]) => void | |
* - Defines a 'set' function | |
* - Only permits calls with keys and values from T | |
* - Example: | |
* T = { key1: string, key2: number } | |
* set('key1', '1') | |
* set('key2', 2) | |
* set('key1', 1) // error: not string | |
* set('key2', '2') // error: not number | |
* set('key3', '3') // error: invalid key | |
* */ | |
type TypedFormData<T extends FormDataKeys<T>> = Omit<FormData, 'get' | 'set' | 'append'> & { | |
get: (key: keyof T) => T[typeof key] | undefined, | |
set: <K extends keyof T>(key: K, value: T[K]) => void, | |
append: <K extends keyof T>(key: K, value: T[K]) => void, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment