Skip to content

Instantly share code, notes, and snippets.

@JanMalch
Last active July 3, 2020 22:26
Show Gist options
  • Save JanMalch/cceeb44511475ab076b9fcf74e99e1f0 to your computer and use it in GitHub Desktop.
Save JanMalch/cceeb44511475ab076b9fcf74e99e1f0 to your computer and use it in GitHub Desktop.
Using TypeScript's features to create a type safe validation flow
// 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
}
// 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)
/**
* 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