3 min read

Type-Safe Reducers using TypeScript - Part 1 - Understanding Type Safety

Type-Safe Reducers using TypeScript - Part 1 - Understanding Type Safety
Photo by Gabriel Heinzer / Unsplash

Understanding Type Safety

Type-Safety is one of the super powers of statically typed programming languages like C#/Java. But for the ones who tries to accomplish anything and everything with these languages finds this also a curse. But a proper use of type-safety could enhance and ease the programming and provides better end to end development experience.

But what about a language like JavaScript that is dynamic in nature. How do we ensure type-safety?

Oh, wait! Does JavaScript support data types? Oh come on, you shouldn't be surprised by this. If you do so, I suggest you stop reading here and head to Mozilla Developer Network site and read about JavaScript and supported data types a bit.

Let's get into our business here. According to Wikipedia

Type safety is the extent to which a programming language discourages or prevents type errors

In the method below we are attempting to find if a string starts with a given value. The code looks a lot easier.

function startsWith(sourceString, findWhat){
  return sourceString.indexOf(findWhat) === 0;

How could one make this to cause errors?
Well, we the humans as developers can! Let's see the various possibilities,

let someString = "Some value";
someString = undefined;
startsWith(someString, 'Some');
Uncaught TypeError: Cannot read property 'indexOf' of undefined

You might say that We should check if "someString" is undefined. Yes, that would solve this problem, would it solve all?

let someString = 6;
startsWith(someString, 'Some');
Uncaught TypeError: sourceString.indexOf is not a function

Nothing that tells you here, hey "startsWith" method accepts only a valid string and it can't be undefined or null.

What if something that tells me this (You know what I mean is TypeScript) and makes me more productive by enabling me to write more stable code faster that breaks less at runtime.

With TypeScript one could harness the power of JavaScript's dynamic nature at runtime and sophisticated type system of TypeScript at compile time. This enables us to write code that is easy to understand and maintain.

The same method If I write using TypeScript, it would look like,

function startsWith(sourceString: string, findWhat: string) {
    return sourceString.indexOf(findWhat) === 0;

If tried to pass undefined,

[ts] Type 'undefined' is not assignable to type 'string'.

And if I tried to pass number,

[ts] Argument of type 'number' is not assignable to parameter of type 'string'.

There is nothing extra that we have written here except the type annotations.

But you must be aware that if this method is part of a JavaScript library and it is invoked by external code where our "startsWith" method is sent a value which is not a string, still the above discussed runtime errors would arise.

This is because "Type checking" is only done at the compile time.
We could avoid them by writing a defensive code and with unit test cases the same can be tested. That's a different world of topics all together. So, let's save it for some other day.

Then this question may arise, is it worth spending time in writing code in TypeScript?

Well, in my opinion it is definitely worth only if you are making use of type annotations properly. If you annotate your variables and function parameters with "any" more often than necessary then it is either you are not using TypeScript to its potential or may be not an option for your specific use case.

I think by now we are sure of the basic problem. Now let's see this problem through a different window called "redux".

If you are not sure of what Redux is, stop right here and go here.

While you are learning, I would have completed writing the Part 2 and updated the link here.