Dmitry Pashkevich Web developer. Productivity geek. Linux user. Tea drinker. Amateur photographer.

7 bad excuses for not using TypeScript

8 min read 2278

Typescript has come a long way since its inception over six years ago and is being adopted by leading web companies. While there may be good reasons to avoid using it, chances are your excuses for not using TypeScript are just bad.

In this article, I’ll cover common concerns like the learning curve, tooling, development speed, sustainability and standards compliance.

1. The learning curve is too steep

It’s important to note that TypeScript is not an entirely new language. Languages like CoffeeScript and Reason dress up JavaScript into the syntax and semantics of other programming languages — Ruby and OCaml accordingly. TypeScript pursues much more conservative goals.

Instead, it takes plain JavaScript and just adds a type system on top of it (TypeScript is a superset of JavaScript). This makes the learning curve extremely lean. Switching to TypeScript from JavaScript is not the same as switching between different languages.

Here’s a code snippet in TypeScript:

class Greeter {
    greeting: string;

    constructor(message: string) {
        this.greeting = message;
    }

    greet() {
        return "Hello, " + this.greeting;
    }
}

Here’s the same code in modern (ES6) JavaScript:

class Greeter {
    constructor(message) {
        this.greeting = message;
    }

    greet() {
        return "Hello, " + this.greeting;
    }
}

As Anders Hejlsberg, a co-creator of the language, puts it, if you know JavaScript, you already know TypeScript. Later in the article, I’ll talk more about the path of converting an existing project to TypeScript.

2. But JavaScript is standard, TypeScript is not

When TypeScript came out in 2012, it brought features like classes and modules, which didn’t become “standard JavaScript” until 2015, when ECMAScript 6th Edition (ES6, or ES2015) was finalized. The original implementation of modules in TypeScript deviated from ES6, but it was updated (maintaining backwards compatibility) to match the ES6 spec in the same year the standard was finalized.

Today, TypeScript language closely follows the ECMAScript spec, implementing most proposals that reach Stage ³¹. This means that when you write TypeScript, you’re writing modern, standards-compliant JavaScript. And thanks to the built-in ES3/ES5 transpiler, the output .js files will run without issues in older browsers.

3. It kills the dynamic nature of JavaScript

If you’ve been working with scripting languages for a while, you’ve come to appreciate the speed of development that they enable. You can freely wrangle data structures on the fly without ever having to declare them up front. This freedom, however, comes at a cost. Dynamically typed programs are much harder to reason about than the statically typed ones since there is no compile-time validation of the data flowing through the program.

Consider this simple example in plain JavaScript:

function greeter(person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

By looking at the code, we can infer that the person parameter should be an Object with properties firstName and lastName. But there’s no guarantee that this will always be the case at runtime.

The larger your project is, the higher the chance type-related bugs will occur.

One way to shield your code against such bugs is through runtime type checks and additional unit tests like this:

function greeter(person) {
    if (!person || !person.firstName || !person.lastName) {
        throw new Error('invalid arguments');
    }

    return "Hello, " + person.firstName + " " + person.lastName;
}

// Jasmine spec:
describe("greeter", function() {
    it("returns greeting on valid input", function() {
        expect(
            greeter({firstName: 'James', lastName: 'Hetfield'})
        ).toEqual('Hello, James Hetfield');
    });

    it("throws on invalid input", function() {
        expect(() => greeter()).toThrowError('invalid arguments');
        expect(() => greeter(5)).toThrowError('invalid arguments');
        expect(() => greeter({firstName: 'Jason'})).toThrowError('invalid arguments');
    });
});

But this solution is very verbose and leaves the responsibility to validate data on the developer. What if instead, we could simply add a type annotation to our function?

interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person: Person): string {
    return "Hello, " + person.firstName + " " + person.lastName;
}

// Jasmine spec:
describe("greeter", function() {
    it("returns greeting", function() {
        expect(
            greeter({firstName: 'James', lastName: 'Hetfield'})
        ).toEqual('Hello, James Hetfield');
    });
});

The above example is much more idiomatic and lets us focus on just validating the business logic in our tests.

TypeScript embraces the dynamic nature of JavaScript by employing a structural typing system and being surprisingly good at type inference, which means that you don’t have to be nearly as explicit with types as you would in C# or Java. Here’s an example of using the function we wrote above in TypeScript:

let user = { firstName: "James", lastName: "Hetfield" };
console.log(greeter(user));

This code successfully compiles. Notice how we didn’t have to explicitly say that the user variable implements the Person interface, nor did we have to define a class that extends it. One of the language’s design goals is not to create a “sound or provably correct type system”, but to “balance between correctness and productivity”.

What’s also important is that the TypeScript compiler doesn’t force you to declare types everywhere, you choose how aggressive you want to be with type safety. You may even decide to apply a different level of type strictness in different areas of your project. Such flexibility is not something that traditional statically typed languages offer.

4. It’s not going to be around in 5 years

I’ve got news for you. Nobody has any idea what languages, tools or frameworks are going to be around in 5 years, especially in the web space. Here’s what a StackOverflow blog author wrote about the lifecycle of JavaScript frameworks:

There appear to be two major phases in JavaScript framework usage. There appears to be a quick ascent, as the framework gains popularity and then a slightly less quick but steady decline as developers adopt newer technologies. These life cycles only last a couple of years.

You work in a fast-moving industry, and if you and your project can seriously benefit from certain technology today, consider adopting it. Even if you swap it with something else in 1–2 years, the benefits you reap during that time would have accelerated your project enough to make it worth it.

5. It’s not community-driven

Typescript was released in 2012 by Microsoft, a proprietary software giant. Considering the reputation of the company and its development platforms, it was easy to perceive that TypeScript was meant to be “a flavor JavaScript for .NET developers”. Perhaps such perception was further reinforced by the fact that Visual Studio was the only IDE at the time with rich support for the language. Or by the fact that the project’s source code was initially published on CodePlex, a Microsoft-run GitHub alternative.

A lot has changed since then. The team behind TypeScript realized that if they wanted to see a broader adoption of the language, they needed to be better embedded in the web development community by providing high-quality tooling and listening to the feedback. They went far beyond merely putting the source code out there while continuing development in a vacuum, but fully embraced the concept of Open Development.

In 2014, TypeScript’s code was moved to GitHub, and the development actually happens there (as opposed to developing elsewhere and just exporting new versions of code to GitHub, as seen in some projects). The project invites contributions in the form of logging bugs, documenting proposals and submitting pull requests. The issue tracker gets regularly looked at and every submission usually gets triaged within a few days. The core team has published the language’s design goals that I referred to earlier, which help the project stay true to its mission while still taking input from the community. They keep an up to date roadmap (a new release now happens roughly every two months), as well as document any breaking changes.

An overview of the activity on the TypeScript project on Github

At the time of writing, all major cross-platform IDEs and text editors like Eclipse, Webstorm, Emacs, Vim, Sublime, Atom, VS Code, have mature support for TypeScript either out of the box or via a plugin. The core team has also put a lot of effort into creating type definition files for interoperability with existing libraries and frameworks written in plain JavaScript (more on that later). Another thing worth noting is a well-documented TypeScript Compiler API that enabled the creation of many valuable third-party language tools. Developers who use Typescript are encouraged to ask technical questions on StackOverflow.

Taking all of that into account and reiterating the fact that TypeScript heavily relies on ECMAScript, I think it’s fair to say that the project is community-driven and has been for the past few years. Here’s what Tom Dale, a co-creator of EmberJS, said about TypeScript in 2017:

Most of all, I continue to be impressed by the professionalism of the TypeScript team. In an ecosystem that can feel built on a house of unmaintained cards, TypeScript’s drumbeat of constant, iterative improvement is refreshing.

6. Converting an existing project is too much work

OK, in order to take full advantage of TypeScript in your project, you will have to spend time declaring types and fixing compiler errors, and that will be somewhat tedious. However, authors built it with the JavaScript ecosystem in mind and provided a smooth on-ramp for adopting TypeScript on an existing project.

Per the official migration guide, you can reap some early benefits by simply running your existing JavaScript code through the TypeScript compiler. At this point, the compiler will catch some low-level bugs like missing return statements at the end of functions or blocks of unreachable code. Then, you can start renaming .js files to .ts one by one and addressing new compiler feedback. The default compiler options are pretty lax, but you can turn on stricter checks. You can even use a different set of compiler options on different parts of your project, letting your teams adopt TypeScript at their own pace, using as much or as little of it as they want. The bottom line is there is a smooth transition path that doesn’t halt development across the company, it’s not an all-or-nothing commitment.

You can choose to convert an existing project to TypeScript gradually, or perform a “big bang” conversion, or simply use it on a new project. There are also community projects like TypeWiz that automatically add missing type information to code.

7. But all of the libraries I use are in JavaScript

To enable interoperability with existing JavaScript code, the language supports TypeScript Declaration Files. For example, if a JavaScript library you use exports a global function called camelize, a TypeScript declaration for it would look something like this:

declare function camelize(s: string): string;

After you import such declaration into your project, the TypeScript will know about the function’s types.

In the same year, TypeScript was released, DefinitelyTyped, a community repository of declaration files for popular libraries, was created. At the time of writing, it contains declarations for over 5,000 JavaScript packages. Using these declarations is extremely easy. For example, if you use Jasmine testing framework in your project, simply run:

npm install --save-dev @types/jasmine

The types will then be automatically included by the compiler, and you’ll get on-the-fly type checking and autocomplete in your code editor. All or most of the packages you use should already have high-quality type declarations created for them, either bundled in or available via the DefinitelyTyped repo. The engineering team at Slack shared their experience:

Looking ahead and thinking about code maintenance, we appreciate the ecosystem around TypeScript. As heavy users of React and the Node/npm ecosystem, the availability of type definitions for third-party libraries is a huge plus. Many of the libraries we import are already TypeScript compatible. If definitions do not ship with the module itself, they are likely to be found in the fantastic DefinitelyTyped project. React, for instance, does not ship with type definitions, yet a simple npm install @types/react installs them with no further configuration required.

Conclusion

Using static type checking helps you eliminate a whole class of bugs, and TypeScript is the most popular static typing solution for a Node/JavaScript project. It may not be worth it on a relatively small or experimental project, but the benefits far outweigh the added overhead on a large-scale project, as proven by companies like Google, Slack, Asana, Ember and others. Hopefully, this article has given you a fresh perspective on TypeScript and addressed some specific arguments against it that are no longer relevant. Maybe it’s time for you to give it another chance.

Are you currently using TypeScript or planning on using it? If not, what’s holding you back?

P.S. It’s worth noting that there is another project that adds static types to JavaScript while preserving the language syntax and semantics, it’s called Flow. Be sure to check it out if you’re looking for alternatives to TypeScript.

¹[^] According to ECMAScript’s standardization process, Stage 3 (“Candidate”) is the fourth out of five “maturity” steps of a standard proposal. It means that the proposal specification is ready for implementation in real world.

Plug: LogRocket, a DVR for web apps

https://logrocket.com/signup/

LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single page apps.

Try it for free.

 

Dmitry Pashkevich Web developer. Productivity geek. Linux user. Tea drinker. Amateur photographer.

One Reply to “7 bad excuses for not using TypeScript”

  1. “This makes the learning curve extremely lean”

    Most people don’t know what “learning curve” means. A steep learning curve actually means that learning increases rapidly with experience, i.e. it’s easy to learn.

    A “lean learning curve” can only mean the person who drew the graph with a sharp pencil and produced a thin (“lean”) line. 🙂

Leave a Reply