Home

Published

- 10 min read

How to prevent Faux-TypeScript code bases

img of How to prevent Faux-TypeScript code bases

TypeScript has joined the ranks of the most popular programming languages. This is great news for TypeScript developers. More companies are going use TypeScript in their projects and their skills are going to be useful for the foreseeable future.

Companies now are in a weird position. There is a business case to convert existing code to TypeScript. Not only would you get the benefits of TypeScript but you now also make the company more attractive for new developers.
However on the other hand, the codebase is working at the moment just fine with JavaScript. It would be time consuming, and costs a lot of money to do the conversion. From a project manager perspective there is no short term ‘Return on Invest’. They will try to cut corners wherever possible.

As a result, conversions are rushed and there is a rise of ’Faux-TypeScript’ code bases. On the surface it looks like TypeScript, however they actually are missing the type-definitions and use very liberally the ‘any’-keyword. This means TypeScript is effectively disabled and it is actually just a JavaScript code-base.

This however creates problems. You create more bugs in a Faux-TypeScript code base compared to a JavaScript or TypeScript code base. When working with JavaScript you have to manually ensure to check if you accidentally introduced a TypeError with your changes. In a TypeScript codebase the compiler will find TypeErrors and you can take care of the next problem.

In a Faux-TypeScript code base, you still expect the TypeScript compiler to find TypeErrors. In this codebase however if you introduce a new error - It is either lost in the thousands of errors the TypeScript compiler outputs, or alternatively it throws no error, because the keyword ‘any’ was used. Now you would say, well then you just manually have to check that as you would have done with a JavaScript codebase. - True, however you are writing your new code in TypeScript, so you tend to forget to do this step significantly more often. In practice you are introducing more bugs and suddenly developers think “TypeScript Development is painful”.

The solution to this simple - the codebase has to be migrated to actual real TypeScript. In order to get there you need to do two things:

  1. Convince management
  2. Ensure that all developers learn and write TypeScript.

Convincing Management

I imagine that a lot of conversations with managers go something like this:

Developer: I want to use TypeScript, I have heard only good things about it.

Manager: How much effort will this take?

Developer: Not much.

  1. Add the typescript compiler
  2. Change the file ending from ‘.js’ to ‘.ts’, as all JavaScript is valid TypeScript
  3. Add types over time

Manager: Awesome, that wont take a lot of time, is basically zero-cost. In addition we save money by not needing to train our existing JavaScript developers to use TypeScript.

Unfortunately this sets the wrong expectations for the manager. He will only allocate a small amount of time for this ‘TypeScript’ thing. The discussion should not be about the minimal steps, but what is the ROI (Return on Invest).

Before you go to your manager you should be clear what you want to communicate to your manager. Do not expect that your manager knows what TypeScript is, you are going to have to educate him and you will have to sell him the idea and he has to buy into the idea.

The best way to convince a manager is to explain him the situation. This can be done by presenting good reasons and a plan how to execute it. This makes it easier for the manager to decide if it should be done and prepare resources to be allocated to this task.

The conversation should be more like this: Developer: I want to use TypeScript. There is a high business value in converting our existing codebase.

Manager: Interesting. How much effort will this take?

Developer: Unclear. We can start immediately implementing the minimal steps. After that we will have a clearer picture to know how much effort it is going to be. Most likely we can convert gradually over the next couple of months our entire codebase as we implement new features.

Manager: Multiple Months? We can’t do that.

Developer: Here are a couple of reasons we definitely should do it

Reasons to convert to TypeScript

Finding Obscure bugs

Just by adding types to the code will most likely reveal several existing bugs in the codebase. This in it self already has an incredible business value.

  1. The customer gets a better product. As the product now less bugs and an overall better quality.
  2. The development team has to spend less time on debugging errors, as they know exactly where they are. Thus the team is available to develop more features.
  3. The support team has less volume of complaints.

Unfortunately the developers will need additional time to fix these new found bugs. This will prolong the time needed to migrate to TypeScript.

Important: I made the mistake of not communicating this early with my manager, and we then had to have several discussions about TypeScript introducing new bugs, while in reality TypeScript just revealed existing bugs.

Development Velocity

Let’s take a look hat how development in JavaScript differs from TypeScript. In this example we just introduced a small typo in a variable name.

JavaScript development cycle is

  1. Write new code with typo
  2. Open Browser
  3. Execute code in Browser
  4. do steps to execute your newly written code.
  5. Discover you have a silly typo
  6. Search for the location of the typo
  7. Fix typo

With TypeScript:

  1. Write new code with typo
  2. Code does not compile. Error message tells you in which file and line to look for error.
  3. Fix typo

You are going to only save a couple of seconds with TypeScript compared to JavaScript. In practice this cycle will happen lets say 10 per hour. These couple of seconds will add up very fast to a couple of minutes.

You also eliminate potential failure points of the long JavaScript cycle. Example: You could get distracted by your browser and drift to another task, you can mess up the steps to execute the code and the switch back to the editor makes you loose the code segment you were working on. All of these things make the cycle even longer. In addition, the long cycle will start to frustrate you. It is just a silly typo, but now you wasted time on the entire cycle to execute the code. If this happens to often you start to question your own abilities. You will execute each step even slower, just to avoid the mistakes. Which in turn will again increase the time needed for this cycle.

Even if you are not convinced. Just think about the last time you had to meet a deadline and you were running low on time. My guess is you would be happy for every shortcut you can get.

TypeScript will increase the development velocity, reduce common errors and increase the confidence that the change to the code will actually work.

Obviously if the developers can work a faster is a great business value.

Earlier Error Detection

The main purpose of TypeScript is to detect the most common error in JavaScript - The TypeError. It has been observed you can prevent 70% of bugs in a code base just by using TypeScript.

During development - if you adjust a function signature, with TypeScript the code will not compiled if this change accidentally broke some other part of the code. Making it very easy to immediately adapt the change - without accidentally introducing a new bug to the system.

Less errors in the codebase is going to be better for the product, thus improving the overall quality and at the same time ensuring that existing functionality still works. Reduces a lot of costs down the line, debugging costs, error removal, support costs etc.

Decrease Onboarding Time

New Developers will have it easier to read and understand the code. A new developer will be able to contribute to the project faster.

Equally this is true for developers that are consuming your code as a library. It makes the library much more comfortable to work with.

In my experience managers do not see a lot of business value in this, because it is so rare that a new team member has to be onboarded. (No matter how high the actual team fluctuation is.)

Encourage Developers to write TypeScript

Developers that started to learn programming with a strongly typed language usually do not have any difficulties to adapt to TypeScript.

Unfortunately developers that learned to program in a dynamically typed language find it quite difficult to work with types. They need additional training to work with TypeScript effectively. I would recommend to read the TypeScript Handbook and taking a free official course from Microsoft Learn.

In practice developers do not have the time to actually do the training. What happens then is that developers tend to get frustrated with the TypeScript compiler errors and then take the shortcut to disable the warning message by either using the ‘any’-keyword or the //@ts-ignore -comment.

To avoid these bad practices, you have to define coding guidelines and enforce them with a linter like ESLint.

What is the any-keyword?

From the TypeScript Handbook - “TypeScript also has a special type, any, that you can use whenever you don’t want a particular value to cause typechecking errors.” - It continues in the Do’s and Don’ts: ”Don’t use any as a type unless you are in the process of migrating a JavaScript project to TypeScript.” As with most manuals, nobody actually reads this second part.

The key point is, there is a valid use-case for this keyword, the important thing is that this is only suppose to be temporary. As this is part of the language itself, you cannot simply disable the usage of the keyword.

Using ESLint to disable the TypeChecking Suppression

Add EsLint to your project

npm i -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser

Configure ESLint

{
 "root": true,
 "parser": "@typescript-eslint/parser",
 "plugins": ["@typescript-eslint"],
 "extends": [
   "eslint:recommended",
   "plugin:@typescript-eslint/eslint-recommended",
   "plugin:@typescript-eslint/recommended"
  ],
 "rules": {
   "@typescript-eslint/no-explicit-any": "error",
   "@typescript-eslint/ban-ts-comment": "error"
 }
}

Important: If you do not want to use the rules from @typescript-eslint/recommended, you should additionally ban the usage of the //@ts-ignore-comment. This comment also allows you to suppress TypeScript errors. Add following rule to your ESLint configuration: "@typescript-eslint/ban-ts-comment": "error"

If you end up with too many errors to fix, you can reduce the sensitivity to ‘warning’. Then fix the code over a longer period of time and when you hit zero warnings, increase the severity back to ‘error’.

Ensure that every developer uses ESLint

The easiest way is to set up a git pre-commit hook, that always executes ESLint. The developer then cannot commit code that does not pass the linter. You can find a full guide how to set this up with the help of husky.js here.

Conclusion

TypeScript is a great tool. It will improve your codebase and your product. Please do not rush the conversion from JavaScript to TypeScript. It is going to slow you down significantly if done incorrectly. Everyone on the team, no matter their role, if it is a manager or a developer contributes to the health of the codebase. I hope this guide helps you to improve your codebase.