Last active
July 3, 2020 22:26
-
-
Save JanMalch/cceeb44511475ab076b9fcf74e99e1f0 to your computer and use it in GitHub Desktop.
Using TypeScript's features to create a type safe validation flow
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
// Define your own interfaces and functions: | |
interface MyForm { name: string; } | |
function getFormData(): Unvalidated<MyForm> { | |
return { name: 'John' } as Unvalidated<MyForm>; | |
} | |
function process(myForm: Validated<MyForm>) { } | |
function isValid(input: any): input is Validated<MyForm> { | |
return input.name != null && input.name.trim().length > 0 | |
} | |
// usage | |
const formData = getFormData(); | |
process(formData); // type error | |
if (isValid(formData)) { | |
process(formData); // ok | |
} |
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
// Define your own interfaces and functions: | |
interface MyForm { name: string; } | |
function getFormData(): Unvalidated<MyForm> { | |
return { name: 'John' } as Unvalidated<MyForm>; | |
} | |
function process(myForm: Validated<MyForm>) { } | |
function validate(input: Unvalidated<MyForm>): Validated<MyForm> { | |
if (input.name == null || input.name.trim().length === 0) { | |
throw new Error("Invalid Form Data!") | |
} | |
return input as any as Validated<MyForm>; | |
} | |
// usage | |
const formData = getFormData(); | |
process(formData); // type error | |
const validated = validate(formData); | |
process(validated); // ok | |
// https://www.typescriptlang.org/play/?ssl=38&ssc=2&pln=25&pc=1#code/PQKhCgAIUhhAnApgQwC6IM6WZAdgewFsBLXZAG0lQE8AHRSfAMz2UIYAMAVDyJ-eFQAWDACZocNepA4ARDgDooMAAJTEtZPDaQurdoxaoReIqQpU6iZZDVXN2wpFnCGyAMaoArhfGpJVsrA4OqQAHJmZOQAPFwANM4AfJAAvJAA3pAA+uoAXLqQAL6QAGTOANzg4KAQ0OGRFqHGaJCkosTuaJjCLcYMXriiiPDk1KQA5pB+OMRYBKiQ1IgLAG4UxH6Iokp1KhiIDABq65uiNnsH9SRRQSFWkACquGvkG12isclpEdcU0QDkTxeb3Qon+CS4iUq1TANh+5koTSELTaHS6WGaCz6kAGQxGY1wk2mrSwwNOO1U+wYQJO73OVKuCNuoWOr1On1SjKiANZIK24N0UKq1WAU0QhHwVVI6HgTA8DAAstQAGICJyZMjsfIYVDwCblIpVJgDTzEfC4SDjZaq+CEWQSAAUAEp8jS2e9okqbYRkukoJAkN54BaNWxEPl-gApfBCXD-IrYLBuvkfL1qoWFI0m1Bmi20eD4dyYDAOwgqtX5XnstO2xJOjKG8DG3Cm82QMldB2kWheVCu5600Ge8u1l2QKsems+jL+4gsLu4HuoBSahgpNK4LzkSgAHx3rUXvZXYYUuuIhGdCnIiEJxlS68gAAZ637IG-hAWAO54RDfgCi8AFvADoAEQAJIDmykDes4EgAIQgU6-qZm+gZeMGB5Lom2C4NQ2ETkOU4ZlUwCil4GDIFaVTuOaOp8Gq9r+JyVqoN6jHIM6lSkZA+aFsWDr8La7FOga75iWJ3GhMMQHgDRuB0R2oKcopiACQxEgieAvFFhgJYqaIIniUZ77cfgADWQA) |
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
/** | |
* Creates a nominal type of name `T` for the data type `D`. | |
* @typeparam T name of the nominal type | |
* @typeparam D the actual data type | |
*/ | |
export type Nominal<T, D> = { _type: T } & D; | |
/** | |
* Nominal type that indicates that the underlying data is not yet validated. | |
* @see Validated | |
* @see Nominal | |
*/ | |
export type Unvalidated<T> = Nominal<'Unvalidated', T>; | |
/** | |
* Nominal type that indicates that the underlying data is validated. | |
* @see Unvalidated | |
* @see Nominal | |
*/ | |
export type Validated<T> = Nominal<'Validated', T>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment