Advanced Typescript patterns

Ensuring that a value has passed through a function

Consider this scenario. A client sends you dates, times, years as strings and you need to store all of them in the DB as Unix time-stamps. But you have to make sure that when client is putting things in, you parse the time according to the correct format and when you’re sending back entities to the client, you’re returning back strings that formatted correctly. To the client, all of them are strings but some are “YYYY”, others are “YYYY-MM-DD” and others are “YYYY-MM-DDTHH:mm”. Your database must store them as numbers for them to be sortable fields.

interface PutBunchOfDatesObj {
date: string; // formatted as YYYY-MM-DD
time: string; // formatted as YYYY-MM-DDTHH:mm
year: string; // formatted as YYYY
}
interface DBBunchOfDatesObj {
date: number;
time: number;
year: number;
}
function putBunchOfDates(dates: DBBunchOfDatesObj): Promise<void>
interface DBBunchOfDatesObj {
// all these My* types are actually just
// strings at runtime. Just their existence
// is a proof that they are correctly formatted.
date: MyDate;
time: MyTime;
year: MyYear;
}
interface MyYear extends String {
// the name of this field doesn't really matter
// as long as it's unique to this interface.
// you can't really do anything with this field and this
// won't even be present in the object so, it's okay
// to pretend that this field isn't there. It only exists on
// the type level and has no runtime significance.
// This is why this technique is sometimes called a "Phantom type"
__my_year__: never;}
function parseMyYear(str: string): MyYear | null {
if (/^\d{4}$/.test(str)) {
return str as MyYear;
} else {
// or throw an exception. Doesn't matter how you
// handle errors.
return null; }}
function myYearToUnix(y: MyYear): number

Type safe object validation

Your API might expect your clients to respect a certain schema for JSON payloads. It would be nice if you could write a declarative schema for the request and have that automatically converted to a type so that intellisense can work properly.

const myValidator = Joi.object().keys({
key1: Joi.string(),
key2: Joi.string().valid("x").valid("y").required(),
key2: Joi.number().required()}).required()

And there’s more

I’ve written previously about neat stuff you can do in Typescript.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store