Just let TypeScript do its thing

It is a well known fact that compile-time errors during development are easier and cheaper to catch than runtime ones in production. Unfortunately people keep forgetting that simple fact. Let me tell you a little story about AWS Lambda hiccup, and how it could easily be avoided.

A developer wrote a simple Lambda function in TypeScript that would receive a parameter of the following type:

interface Notification {
    slack?: {
        notify: boolean
    };
    github?: {
        notify: boolean
    };
}

The logic is simple – if slack.notify is true – send slack notification. If github.notify is true – send github commit status notification. The function deployed without issues, and it does send slack notifications. There is one problem: often it would send the same slack notification 3 times in a row.
What could be the reason? Let’s take a look at actual function. It goes something like this:

function notify(notification: any) {
 
    if (notification.slack.notify) {
        // ...
    }
 
    if (notification.github.notify) {
        // ...
    }
}

Notice anything wrong with it? Yes, that’s right – the type of the parameter is defined as any, which means no type checks is being done by TypeScript. Now, as you notice both slack and github properties are optional. What will happen if the function receives value like

{
   slack: {
      notify: true
   }
}

The first if condition is satisfied, and the function sends slack notification. But the second one will throw an exception

Cannot read property "notify" of undefined

because github property is not present in this value. Function throws the exception, and Lambda invocation fails. By default a failed Lambda re-tries invocation 2 times. So the slack notification will be send 2 more times. Mystery solved.

How could this be avoided? By defining function parameter as strongly typed. If you do so – TypeScript won’t let you compile the code as is. Moreover in IDEs like VS Code you will get visual representation of the error:

TypeScript error

The only way TypeScript will let this thru if you specify properties as optional

function notify(notification: Notification) {
 
    if (notification.slack?.notify) {
        // ...
    }
 
    if (notification.github?.notify) {
        // ...
    }
}

With this version, in the above scenario if github property isn’t there – it won’t even bother to check for .notify value, the second if condition will fail before that.

Moral of this story: Let TypeScript do its thing, the types are there for a reason, and often the reason is to prevent you from shooting yourself in the foot.

Leave a Reply

Your email address will not be published. Required fields are marked *