Type guards, type predicates, assertion signatures, and branded types in TS
Mohammad Jawad (Kasir) Barati
Posted on November 11, 2024
I love TS for a reason, and that is how easy and predictable it makes your code. Let's talk about them and how you might wanna utilize them.
Let's say we're building a smart building management system. It is intended to be used in industrial companies1, and health industry that use various IoT sensors to monitor and maintain optimal environmental conditions across different zones (offices, hallways, operating rooms, warehouses, etc).
So we have a bunch of sensors here and there to gain insight and unique data points that contribute to the overall goal of being energy efficiency, and comply by the regulatory compliances.
Heads up
I've added a link to this post's GH repo since it was not really easy to copy and paste them here to. But what I did here was explaining the requirements verbally so that you know why I did certain things in the code.
First let's define a bunch of contrived-like scenarios that ain't far from a real world app:
-
We need to sanitize and throw error in case something is off entirely before storing data in our database. Like for example here we have a motion sensor installed on a robot and when it moves we wanna record it.
But before that we need to make sure it is really moving and speed is a valid speed (it cannot be negative or zero). Does not this code look super intuitive and easy to follow:
const sanitizedMotion = structuredClone(motionDto); assertIsMoving(sanitizedMotion); assertNotZeroOrNegative(sanitizedMotion.speed); sanitizedMotion.speed = this.sanitizeSpeed(sanitizedMotion.speed); // ... return await this.dbClient.create(sanitizedMotion);
-
Or what if we allow our users to configure how sensitive is the motion sensor. Then do not we need to perform sanity check every once in a while automatically to make sure that the sensitivity level is not causing us to assume something is moving too often or is not just because they did misconfigured it. Maybe something like this:
export async function sanityCheckSensitivity(motionDto: MotionDto) { // BTW this pattern is commonly know as Decompose Conditional if (isStatic(motionDto)) { const lastMovingRecord = await motionRepository.getLastMovingRecord(motionDto.deviceId); const lastMovingDate = DateTime.fromISO( lastMovingRecord.timestamp, ); const currentStaticDate = DateTime.fromISO( motionDto.timestamp.toISOString(), ); const diff = currentStaticDate.diff(lastMovingDate, 'hours'); if (diff.hours > 12) { console.warn`Sensitivity level is too low for device ${motionDto.deviceId}!`; } return; } // Here it knows that the motion data was not static and it was actually sent because of some movements const lastStaticRecord = await motionRepository.getLastStaticRecord( motionDto.deviceId, ); const lastStaticDate = DateTime.fromISO(lastStaticRecord.timestamp); const currentMovingDate = DateTime.fromISO( motionDto.timestamp.toISOString(), ); const diff = currentMovingDate.diff(lastStaticDate, 'hours'); if (diff.hours > 12) { console.warn`Sensitivity level is too high for device ${motionDto.deviceId}!`; } }
-
Or what if you wanted to send a notification on a moving robot that has high power consumption, something like this:
export function notifyMeOnMovingHighConsumptionDevice( motionDto: MotionDto, meterDto: MeterDto, ) { // Another Decompose Conditional if (!isPowerConsumptionHigh(meterDto)) { return; } assertIsMoving(motionDto); console.warn`Current power consumption for device ${motionDto.deviceId} is high!`; console.warn`This could be caused because it is moving according to sensor ${motionDto.sensorId} with the speed of ${motionDto.speed}`; }
GH repo
Here you can find all the implementation details you need to know of.
If you think I could've done something better please write a comment here, open an issue, send me a DM on social media or use any means of communication suits you best and share your thought with me. I appreciate it.
Learn more
Follow me here:
- Instagram: https://www.instagram.com/node.js.developers.kh/
- Facebook: https://www.facebook.com/kasirbarati
- X: https://x.com/kasir_barati
- YouTube: https://www.youtube.com/@kasir-barati
- GitHub: https://github.com/kasir-barati/
- Dev.to: https://dev.to/kasir-barati
- LinkedIn: https://linkedin.com/in/kasir-barati
Footnotes
-
To me an industrial company usually encompass sectors like manufacturing, oil and gas, automotive, chemical production, and heavy machinery. ↩
Posted on November 11, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 11, 2024