TypeScript: Why JavaScript Developers Are Making the Switch

What TypeScript Adds to JavaScript

TypeScript is a statically typed superset of JavaScript developed by Microsoft that compiles to plain JavaScript. Every valid JavaScript programme is a valid TypeScript programme — TypeScript adds optional static type annotations to JavaScript without removing any JavaScript capability. The type annotations allow developers to specify what types of values variables, function parameters, and return values can hold, and the TypeScript compiler checks these specifications at compile time, reporting type errors before the code runs rather than at the runtime moment when a type error would cause a crash or unexpected behaviour in production.

The TypeScript adoption trajectory that most clearly reflects its value: TypeScript has grown from a Microsoft internal tool to the default choice for new JavaScript projects among professional developers. The Stack Overflow Developer Survey consistently shows TypeScript in the top five most-loved programming languages, and the State of JS survey shows TypeScript usage growing from approximately 20% of JavaScript developers in 2017 to over 70% in 2023. The major JavaScript frameworks and libraries (React, Vue, Angular, Node.js, Deno) have all added or improved TypeScript support, and most new open-source JavaScript projects are written in TypeScript.

The Problems TypeScript Solves

The JavaScript bug category that TypeScript most reliably prevents: the runtime type error that occurs when a function receives a value of an unexpected type. The JavaScript function that expects a number but receives a string, or the method that is called on null or undefined, fails at runtime with an error that TypeScript would have detected at compile time. In a large JavaScript codebase where a function is called from dozens of places, the TypeScript error that appears when the type of the argument does not match the function’s expected parameter type catches the mismatch at the call site rather than in the error logs after the mismatched value causes a problem in production.

The developer experience improvement that TypeScript most clearly provides beyond error prevention: the autocomplete and intellisense capability that typed information enables. The developer who calls a function and sees a tooltip showing all available parameters and their types, or who accesses a property on an object and sees the full list of available properties with their types, has information that reduces the need to consult documentation and reduces the errors that arise from misspelling property names or passing arguments in the wrong order. The IDE experience with TypeScript is significantly more productive than with plain JavaScript because the type information makes the code self-documenting at the point of use rather than requiring the developer to navigate to the definition or find the documentation.

TypeScript Fundamentals

The TypeScript type system elements that most clearly distinguish TypeScript from plain JavaScript: the primitive type annotations (string, number, boolean, null, undefined) that can be applied to variables and parameters to restrict what values they can hold, the interface and type alias declarations that describe the shape of objects (specifying which properties they must have and what types those properties must be), the union types that allow a value to be one of several types (string | number means a value that can be either a string or a number), and the generic types that allow functions and classes to work with values of any type while preserving type information through the operation.

The TypeScript feature that most improves safety in real-world codebases: the strict null checking that is enabled by the strict: true TypeScript configuration. Without strict null checking, every variable in TypeScript can potentially be null or undefined even if its type annotation does not include null or undefined — mirroring JavaScript’s permissive default. With strict null checking enabled, null and undefined are only assignable to variables whose types explicitly include them, and the TypeScript compiler requires every variable that might be null to be checked for null before it is used. The nullability-related bugs that are among the most common JavaScript runtime errors become compile-time errors with strict null checking enabled.

Migrating a JavaScript Project to TypeScript

The TypeScript migration approach that most efficiently adds TypeScript to an existing JavaScript codebase without requiring a complete rewrite: the incremental migration that adds TypeScript file by file, starting with the most critical or frequently modified modules. TypeScript allows JavaScript and TypeScript files to coexist in the same project, with the allowJs compiler option enabling JavaScript files to be included in the TypeScript compilation and the checkJs option enabling type checking of JavaScript files without renaming them. The migration that begins by adding TypeScript to new files and gradually converts existing files has a lower upfront cost than the complete migration and produces working code at every stage.

The TypeScript configuration option that most enables productive incremental migration without being overwhelmed by type errors in partially migrated code: the noImplicitAny flag that, when disabled (the default in permissive configurations), allows variables whose type cannot be inferred to implicitly have the any type rather than reporting a type error. The allowJs: true, checkJs: false, noImplicitAny: false configuration provides the TypeScript infrastructure (tooling integration, module resolution, compilation) with minimal type checking obligations, allowing the team to add type annotations incrementally without being blocked by the type errors that strict TypeScript would require to be resolved before compilation succeeds.

TypeScript in the Ecosystem

The TypeScript ecosystem support that most enables productive TypeScript development: the DefinitelyTyped repository that provides community-maintained type definitions for thousands of JavaScript libraries that were not written in TypeScript. The React library is written in JavaScript but has comprehensive type definitions in @types/react that enable TypeScript development with React; the Express.js library similarly has @types/express; the lodash utility library has @types/lodash. The availability of type definitions for the overwhelming majority of popular npm packages means that TypeScript projects can use the full JavaScript ecosystem without sacrificing type safety.

The TypeScript adoption consideration that most affects team productivity during the transition: the learning curve for developers who are new to static typing. The TypeScript developer who comes from a dynamically typed background must adjust to specifying types explicitly, understanding the type system’s rules about type compatibility and inference, and reading and writing the type-level code that describes the shapes of data structures. The investment in TypeScript knowledge pays dividends that compound over time as the type system catches more bugs and provides more IDE assistance — but the initial productivity dip during the learning curve is real and should be planned for, particularly when transitioning an existing team to TypeScript for the first time.

ALL LATEST ARTICLES

Related Articles