SitePen is a huge advocate for TypeScript and the benefits of having well-typed code. TypeScript is especially powerful when used by medium and large teams that want to find ways to increase their overall confidence in their code. One of the questions we get asked often is how can we migrate a codebase that is currently written in JavaScript to TypeScript. Many of our customers are happy to find out that type checking can be gradually added without a significant rewrite or large up-front cost.

This post will help guide you through progressively adding TypeScript to a JavaScript application. Like all projects, we highly recommend getting a feel from your team on what they expect and an understanding of where your project can benefit most from a type system for the least amount of effort. New to TypeScript coding? Read our TypeScript guide here, first.

The First Step in Adding TypeScript to JavaScript Applications

The first step in adding TypeScript to a project is adding a tsconfig file which configures the TypeScript compiler and the relevant resources in your project or application. TypeScript can automatically create this file for you by installing TypeScript in your project using npm install typescript and running tsc --init.

Now that we have a tsconfig, we need to instruct the TypeScript compiler to type check JavaScript files. We can do this by adding the allowJS, checkJS, and noEmit configuration flags.

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "jsx": "react",
    "noEmit": true,
    "allowJs": true,
    "checkJs": true,
    "strict": true
  }
}

Sample tsconfig file

The allowJS and checkJS flags instruct the TypeScript compiler to compile and check JavaScript files for type errors. TypeScript does this by making a number of assumptions about the code based on value assignment and, if present, JSDoc comments. The noEmit option tells TypeScript that we only want to run type checking and do not want the compiler to output any transpiled code.

Once a tsconfig file is present, VSCode (or your favorite IDE) should detect that TypeScript is used and automatically type check your code. You may also run tsc from the command line and it will return a list of type warnings and a non-zero exit code if any issues exist.

Resolving Type Warnings in JavaScript

It’s not unusual for TypeScript to report hundreds of type warnings on its inaugural run. Don’t worry, most of these warnings will be easy to resolve! A majority of these warnings will go away after we update your tsconfig and provide any missing type information to the compiler. For this next section, we will be working with compiler options. The TypeScript Handbook has a list of all TypeScript compiler options.

First, make sure that tsconfig’s target property matches the version of ECMAScript used by your project. Most Node.js projects, Babel projects, or projects targeting only modern browsers will need to change this value. You may also explicitly provide a list of libraries to be included using the lib option. TypeScript will tell you when it finds any code that doesn’t match the version of ECMAScript and the libraries you have added.


TypeScript warns that Set was added in ES2015 and this could be a potential error.

Next, types for your application’s external dependencies need to be added to your project. . Some projects will include their own set of type definitions that will automatically get used by TypeScript. Most other projects will have ambient types available on Definitely Typed. Ambient types include only type definitions for a project (i.e. only types, no code) and they are used by TypeScript to understand external libraries. Type definitions can be installed through npm from the @types group. For instance, to install React types run npm install @types/react.


This error is due to missing React types. Installing @types/react will fix this.

React, or other projects using JSX, will need to include the jsx option in their tsconfig file (usually tsx: “react”). This will tell TypeScript to use its JSX parser to identify issues with JSX syntax and usage.


This error indicates that the jsx flag is missing.

By this point, any remaining type warnings should be directly related to your project’s source code. You will need to go through the remaining errors and determine if the warning represents an actual issue that needs to be resolved or if the warning is due to TypeScript incorrectly inferring types from the code. There are a number of ways to solve the latter by either providing more accurate type information or ignoring the problematic type, line, or file entirely.

One of the best ways to resolve a type warning is by providing the correct type information to TypeScript. The best way to do this in a JavaScript codebase is by using JSDoc. TypeScript uses JSDoc comments to resolve types and the comments help to identify and enforce the typed values. More complex types can be defined in a .d.ts file. The file should have the same name as the file it is providing types for and TypeScript will use this file in the same way it uses types from Definitely Typed. While this is good for expressing more complex types using TypeScript’s type system, it does have the disadvantage of existing in a separate file which can lead to making updates to the codebase and forgetting to update the corresponding type definitions.

The other way to resolve type warnings is by ignoring them. TypeScript has several comments that may be provided to indicate how files should be checked.

  • @ts-nocheck will tell the compiler to skip checking the entire file
  • @ts-ignore will skip checking the next line
  • @ts-expect-error (TS 3.9+) works the same as @ts-ignore but if type error is not found it will produce an error

Another option is typing module imports and exports as any in a .d.ts file. The TypeScript compiler will see this and allow the value to be used in any manner. Finally, if your tsconfig file has the strict option set, this enables a number of strict checking options for the compiler. Setting strict to false or disabling some of the strict checking options, like noImplicitAny, can eliminate a whole class of errors.

It’s worth noting that ignoring type warnings through block exclusions, any type, or setting strict to false will make your codebase less type-safe. In the long term, it’s worth making sure that types are correct and as relevant as possible for the most used portions of your codebase.

TypeScript and webpack

Once you’ve resolved most of the type warnings caused by the TypeScript compiler you can look at integrating TypeScript into your build process. For webpack, this is as easy as adding the ts-loader module and including it as part of the webpack configuration. If your tsconfig file has noEmit set to false, then it should also be removed so webpack will receive output from TypeScript. Webpack has an excellent guide for adding TypeScript to a webpack build.

TypeScript and Babel

Babel has excellent support for using TypeScript as a type-checker. This is great for teams that want to add type safety without changing their transpiler to TypeScript. Simply add @babel/preset-typescript to the project’s babel configuration and ensure that noEmit is true in the tsconfig file.

Conclusion

The TypeScript team has gone to great lengths to make progressively adding type-checking to an existing project a quick and painless experience. The compiler is more intelligent than ever at inferring types automatically through their usage and catching common mistakes.

We highly recommend teams consider adding TypeScript to their existing projects. Type-safe code allows teams to write better code in less time with more confidence. When added to continuous integration, TypeScript will eliminate a whole class of common errors and assumptions that can often slip into production and ruin your day.

Need help converting your codebase to TypeScript? Contact us to discuss how we can accelerate your timeline and improve your code quality!