TypeScript

Case Study - Add Function in JS vs TS

We are going to take a look at how to implement the “add-numbers” function. The purpose of the “add”-function is to add two numbers, it takes as an input two numbers and outputs a single number. We will compare the JavaScript with the TypeScript implementation.

JavaScript Solution

The straightforward implementation would be just to use the ’+’ operator.

const add = (a, b) => {
  return a + b;
};

const result = add(1 + 1);
console.log(result); //2

When passing numbers to this function everything works as expected. However this implementation is flawed. It is not restricted to numbers. You could pass any datatype and JavaScript will use the ’+’ operator on them. This will result in that the function returns an unexpected result:

// This argument will be converted by JavaScript to add(undefined, undefined); with the result of NaN
add(); //NaN

// The number is converted to a string and then concatenated
add('text', 3); // 'text3'

// Object is converted to a string and then concatenated
add({ a: 12 }, 1); //'[object Object]1'

Adding TypeSafety

We can improve the implementation by adding runtime checks. This will ensure that we return a number or throw an error.

const add = (a, b) => {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  } else {
    throw new TypeError('Passed Arguments are not numbers');
  }
};

try {
  const result = add(1 + 1);
  console.log(result); //2
} catch (e) {
  console.error(e);
}

Adding runtime checks, will result in a higher complexity of the code, more lines of code and needs more processing during runtime. You also have more effort using the function as now you will have to write error handlers for every call of the function.

JSDoc

A popular alternative is to rely on your IDE or Editor to see potential errors in your code. If we write JSDoc comments many IDEs/Editors can read that information and then can highlight errors when we call the function.

You can enable Check JS in Vscode by adding following line to settings.json:

    "javascript.implicitProjectConfig.checkJs": true,

The Documentation string would look like this:

/**
 * Add Numbers
 *
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
const add = (a, b) => {
  return a + b;
};

VSCode will highlight the similar errors as if you would be using TypeScript. This is no surprise, because VSCode is using TypeScript to analyse your code.

However using JSDoc comes with its own issues:

  • the comment must be kept up to date
  • No automatic checking of all references to the function (i.e. refactoring is hard)
  • Still permits things TypeScript would reject
  • Developers still can just ignore or forget to write documentation

Conclusion JavaScript

While this solution would solve the issue, most developers would not take the time to ensure runtime savety. Many times these checks are written when something goes wrong in production. This is problematic, because all it may be not obvious which function is causing the issue and a lot of time spent finding and fixing those bugs.

Additionally it is a waste of resources to force developers to write similar typechecks over and over again for every function. They would need to be maintained and adjusted every time. - The alternative to this is writing code in TypeScript.

Rewriting in TypeScript

TypeScript adds a type-system to JavaScript. By simply declaring the types we can ensure typesafty during compile time.

The code for the add-function would look like this.

const add = (a: number, b: number): number => {
  return a + b;
};

const result = add(1 + 1);
console.log(result); //2

The function works exactly as before. Lets now try to do the same JavaScript calls as before:

add(); //Error: Expected 2 arguments, but got 0.ts(2554)

add('text', 3); // Error: Argument of type '"text"' is not assignable to parameter of type 'number'.ts(2345)

add({ a: 12 }, 1); //Error: rgument of type '{ a: number; }' is not assignable to parameter of type 'number'.ts(2345)

You will get compile time errors. You will have to fix these errors in order to compile your application again. Basically you detected bugs in your code before you delivered the code and now you have to fix them before continuing development.

Additionally editors like VSCode, run a ts-language-checker in the background of the application, you will see during development immediate feedback and autocomplete suggestions while developing. Increasing your development speed.

Note: Some people argue, that TypeScript only gives you a ‘false sense of security’. Because during runtime the code is executed as JavaScript thus TypeErrors can still happen when using TypeScript. This is a problem which occurs when data coming from outside the application is being processed by TypeScirpt (i.e. server responses, user input). In those special cases you still need to write runtime checks into your code, that is how you prevent TypeErrors in your code during runtime. - However the amount of runtime checks you will have to write is drastically reduced.

Conclusion

Using TypeScript will allow you to catch some bugs in your code faster than before. You can reason about what the code does much faster and there is great support of TypeScript in Editors/IDEs.