An Overview of TypeScript

Last updated Aug 17, 2021typescriptguides

TypeScript is an open-source language which builds on JavaScript, most commonly used programming language on earth, by adding static type definitions.

“TypeScript is JavaScript that scales. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.” - typescriptlang.org

Maintained by GitHub owner Microsoft, TypeScript has climbed from seventh place in 2018 and 2019 to fourth overall in 2020 according to Octoverse. TypeScript is also the dominant JavaScript flavor since 2017 according to Stage of JS 2020, followed by PureScript, Reason, Elm, and ClosureScript.

Using TypeScript unlocks following sound benefits:

  • Linting tool for types
  • Great for the maintainability of long-term projects
  • Take advantage of in-editor suggestions/refactors
  • Catch errors in compile-time or while working on your editor
  • Easy integration with build tools (Webpack, Rollup…)

Learning Curve

Let’s assume that you were convinced by benefits of using TypeScript over JavaScript in a big project. How steep is the learning curve for you as an experienced JavaScript developer with or without previous statically typed language experience?

TypeScript doesn’t change how your code runs, you’ll still have to learn how JavaScript works in order to write code that actually does something. It’s important to remember that TypeScript uses the same runtime as JavaScript.

In my experience, the TypeScript learning curve is low when you experienced with Javascript and a static typed language. Majority of difficult time is to wrestle missing types.

TypeScript is a language very much in the growth phase of its life. It will pay off in big projects with many contributors, despite following overheads rated from low to high effort.

  • Project configuration
  • New syntax old habits
  • Type declarations
  • Beyond JavaScript

Project configuration

TypeScript exposes hundreds of compiler options, it seems flexible to machine but intimidating to human. Most developers will copy recommended configs somewhere, understand some common options and call it a day.

You can always go back to check tsconfig reference when something doesn’t work as expected.

New syntax old habits

TypeScript knows the JavaScript language and will generate types for you in many cases. Be aware that many dynamic design patterns in JavaScript make it difficult for types to be inferred automatically.

Pretty sure you’ll bring your OOP knowledge from previous statically typed language like Java to TypeScript, but be aware following differences:

  • JavaScript is prototype-based object-oriented. How JavaScript allows you to create hierarchies of objects and to have inheritance of properties and their values if different from class-based traditional OOP.
  • Functions are first-class citizens, and functional composition is preferred over class hierarchy.
  • In TypeScript, every type is just a set, and you work with types in a set-theoretic way. Not a single exact type mapping one-to-one between runtime and compile-time.
  • TypeScript’s type system is stripped at compile-time, information about the instantiation of a generic type parameter is not available at runtime.

Type declarations

TypeScript’s type system aims to make it as easy as possible to write typical JavaScript code without bending over backwards to get type safety.

TypeScript uses the type any whenever it can’t tell what the type of an expression should be. To take advantages of type system, you’ll need type declarations literally everywhere including your own codes and 3rd-party libraries.

TypeScript needs JavaScript’s ecosystem to survive. If you’re a library developer, you should learn how to write declaration file to match how your library is consumed.

As consumer, best to use packages written in TypeScript or included declaration files. Otherwise, downloading the corresponding @types package from DefinitelyTyped, type declaration packages should always have the same name as the package name on npm, but prefixed with @types/.

TypeScript vs JavaScript

TypeScript has been around since 2012, offers all of JavaScript’s features, adds an additional type system layer, and built with the JavaScript ecosystem in mind.

All valid JavaScript code is also TypeScript code. You might get type-checking errors, but that won’t stop you from running the resulting JavaScript. While you can go for stricter behavior, that means you’re still in control.

Adopting TypeScript is not a binary choice, you can start by annotating existing JavaScript with JSDoc, then switch a few files to be checked by TypeScript and over time prepare your codebase to convert completely.

TypeScript’s type inference means that you don’t have to annotate your code until you want more safety.

The TypeScript team contributes to the TC39 committees which help guide the evolution of the JavaScript language. When new features have reached stage 3, then they are ready for inclusion in TypeScript.

TypeScript tends to be more verbose than JavaScript, especially when we get into more complex things like Generics. When we begin to work with TypeScript, we might get a bit lost applying several patterns like type guards.

Before migrating to TypeScript from JavaScript, you must keep following heads-ups in mind and plan your migration carefully before making a move:

  • Static typing matters more in team
  • Way more complicated than expected
  • The migration has to be gradual
  • Full typing coverage obsession is real
  • Many libraries don’t have typings
  • It’s not really safe at runtime
  • Documentation mostly in JavaScript
  • There is no going back

Beside adding a type system layer on top of JavaScript, TypeScript also has developed it own features to better reflect as a powerful static typed programming language compares to other traditional ones.

Keep in mind these features will be stripped off or transpiled to JavaScript at compile-time.

Typescript is a superset of JavaScript so you have more power in what you can do. Beside the basic types and utility types, here the non-exhaustive list:

  • Enums - not a type-level extension of JavaScript, define a set of named constants, used to document intent, or create a set of distinct cases.
  • Namespaces - a TypeScript specific way to organize code, are simply named JavaScript objects in the global namespace, can span multiple files.
  • Triple-Slash Directives - are single-line comments containing a single XML tag, contents of the comment are used as compiler directives.
  • Abstract Classes - serve as a base class for subclasses which do implement all the abstract members, can also contain abstract methods and abstract fields that hasn’t had an implementation provided.
  • Generics - one of the main tools in the toolbox for creating reusable components, you can write generic types, generic classes, and generic constraints.

TypeScript vs Babel

TypeScript and Babel let you use virtually all of the new features that ES6 brings today, without sacrificing backwards compatibility for older browsers.

Babel is more like TypeScript compiler (TSC), the JavaScript code after transformed by TSC or Babel is clean, simple code which runs anywhere JavaScript runs: In a browser, on Node.JS or in your apps.

Both support some kinds of optimization out of the box at compile time. Doing all of these optimizations manually would lead to sprawling, unreadable, unmaintainable code, but by delegating this work to our compiler, we get to write nice, idiomatic code, and have our toolchain take care of the rest.

Both can be used in the same projects by using Babel’s preset-typescript to generate your JS files, and then using TSC to do type checking and .d.ts file generation.

TypeScript vs Flow

TypeScript is often compared to Flow as a static type checker for JavaScript. Both allow you to write a safer JavaScript by adding type annotations and stripped away at compile time by compiler.

The syntax differences between Flow and TypeScript isn’t significant. They both support similar types like the usual JavaScript data types, literal types, union types, conditional types, etc. Also, both TypeScript and Flow use similar syntax for type annotations.

TypeScript has more support than Flow does with libraries, frameworks, and it’s used more pervasively in apps because of that. They both provide very similar type checking abilities which retain the flexibility of JavaScript.

TypeScript definitely wins in terms of the quantity, resources, and documentation available.

TypeScript with React

TypeScript can be used for static type checking in React when TypeScript supports JSX and React has typings from Definitely Typed.

React is a popular library for creating user interfaces. It provides a JavaScript abstraction for creating view components using a JavaScript language extension called JSX. To understand how TypeScript works with React components you may want a primer on generics.

JSX is an XML-like syntax extension to ECMAScript without any defined semantics. It’s NOT intended to be implemented by engines or browsers. It’s NOT a proposal to incorporate JSX into the ECMAScript spec itself. It’s intended to be used by various preprocessors (transpilers) to transform these tokens into standard ECMAScript.

import * as React from 'react'

export interface GenericListProps<T> {
  items: T[];
  itemRenderer: (item: T) => JSX.Element;
}

export class GenericList<T> extends React.Component<GenericListProps<T>, {}> {
  render() {
    const {items, itemRenderer} = this.props

    return <div>{items.map(itemRenderer)}</div>
  }
}

TypeScript ships with three JSX modes: preserve, react, and react-native. These modes only affect the emit stage - type checking is unaffected. You can specify this mode using either the --jsx command line flag or the corresponding option jsx in your tsconfig.json file.

  • preserve: will keep the JSX as part of the output to be further consumed by another transform step like Babel.
  • react: will emit React.createElement, does not need to go through a JSX transformation before use, and the output will have a .js file extension.
  • react-native: is the equivalent of preserve in that it keeps all JSX, but the output will instead have a .js file extension.

Conclusion

The debate whether to use TypeScript is over, as library maintainers you should (or even must) support typings, as app developers you can get away in personal projects but often required in enterprises.

In 2021, people expect you to know JavaScript slash TypeScript not just only vanilla JavaScript. You’ll see that more often in frontend job descriptions. Many open-source projects and enterprises are migrating to TypeScript.