July 15, 2024

Introduction to TypeScript in 2026: static typing, satisfies, decorators and more

Photo of Marco Orta Marco Orta | 23 mins read
Compartir
Code editor showing TypeScript types with autocomplete

1. Introduction

1.1 What is TypeScript?

TypeScript is an open-source programming language developed and maintained by Microsoft. It was created to improve and extend the capabilities of JavaScript, the most popular scripting language in web development. Unlike JavaScript, TypeScript is a typed superset that compiles down to plain JavaScript, which means that all JavaScript code is also valid TypeScript.

At its core, TypeScript adds an extra layer of tooling that lets developers write safer, more predictable code. The defining feature that sets TypeScript apart is its static type system. While JavaScript is dynamic and flexible — which can lead to hard-to-debug errors in large applications — TypeScript introduces static types that are checked at compile time, helping you catch and fix bugs before the code ever runs.

1.2 History and evolution of TypeScript

TypeScript was first introduced in October 2012 and has evolved significantly since then. Version 1.0 was released in 2014, marking the beginning of its wider adoption in the developer community. Since its creation, TypeScript has grown in popularity rapidly, thanks to its ability to improve productivity and code quality in large, complex projects.

Microsoft has continued investing in TypeScript, shipping regular updates that have improved both its features and its performance. The TypeScript ecosystem has also grown substantially, with many popular libraries and frameworks — Angular being a prime example — adopting TypeScript as their preferred development language.

1.3 The importance of static typing

Static typing is one of TypeScript’s most significant features. In a statically typed language, variables have types that are known at compile time. This is in contrast to JavaScript’s dynamic typing, where types are determined at runtime. Static typing provides several key advantages:

  1. Early error detection: By checking types at compile time, TypeScript can catch many common mistakes before the code runs, significantly reducing the number of runtime errors.
  2. Improved code intelligence: Editors and IDEs can offer better autocomplete and code navigation thanks to the type information TypeScript provides. This boosts developer productivity by reducing the time spent hunting down and fixing bugs.
  3. Easier code maintenance: In large, multi-developer projects, static typing makes code easier to understand since types act as a form of inline documentation. This makes the codebase easier to maintain and scale over time.

In short, TypeScript brings robustness and clarity to JavaScript development, making it a valuable tool for developers who want to build more solid, maintainable applications. Throughout this article we will explore in detail how TypeScript achieves these benefits and how you can start using it in your own projects.

2. Installation and Configuration

2.1 Installing TypeScript

To start using TypeScript, you first need to install it in your development environment. The most common and recommended way is through npm (Node Package Manager), which ships with Node.js. If you don’t have Node.js installed yet, you can download it from nodejs.org.

Once Node.js is installed, open your terminal or command line and run the following command to install TypeScript globally on your system:

npm install -g typescript

This command downloads and installs TypeScript, letting you use the tsc (TypeScript Compiler) command from anywhere on your system.

2.2 Basic compiler configuration

After installing TypeScript, it’s important to configure the compiler so it works correctly with your project. TypeScript configuration is done through a file called tsconfig.json, which defines compiler options and specifies which files should be included in the compilation.

To create a tsconfig.json file in the root directory of your project, run:

tsc --init

This command generates a tsconfig.json with a basic configuration. Here’s an example of what it might look like:

{
  "compilerOptions": {
    "target": "es6",                   // Specifies the JavaScript version to compile to
    "module": "commonjs",              // Defines the module system to use
    "strict": true,                    // Enables all strict type checks
    "esModuleInterop": true,           // Allows interoperability between ES and CommonJS modules
    "skipLibCheck": true,              // Skips type checking in library definition files
    "outDir": "./dist",                // Output directory for compiled files
    "rootDir": "./src"                 // Root directory of TypeScript source files
  },
  "include": ["src/**/*"],             // Files and directories to include in compilation
  "exclude": ["node_modules", "dist"]  // Files and directories to exclude from compilation
}

This basic configuration is a solid starting point and you can adjust it to meet your project’s specific needs.

2.3 Editor integration

One of the great benefits of TypeScript is its excellent integration with modern code editors such as Visual Studio Code (VSCode), Sublime Text, and others. Here’s how to set up some of the most popular editors to work with TypeScript:

Visual Studio Code (VSCode):

VSCode is one of the most recommended editors for TypeScript, thanks to its outstanding built-in support. To get the most out of TypeScript in VSCode, make sure the official TypeScript extension is installed — it usually comes pre-installed. This extension provides advanced features like code autocomplete, type navigation, and debugging.

Sublime Text:

To work with TypeScript in Sublime Text, install the TypeScript package via Package Control. Open the command palette (Ctrl+Shift+P), select “Install Package”, and search for “TypeScript”. Once installed, the package provides features like autocomplete and type checking.

Other editors:

Most modern editors have TypeScript support, either natively or through plugins and extensions. Check your preferred editor’s documentation for the best TypeScript configuration and optimization practices.

With TypeScript installed and properly configured, you’re ready to start writing more robust and maintainable code. In the sections below, we’ll dive into the core and advanced concepts of TypeScript and explore how to get the most out of this powerful language in your projects.

3. TypeScript Basics

3.1 Primitive types

Like many programming languages, TypeScript uses primitive types to define variables. These primitive types provide a solid foundation for TypeScript’s static type system. The most common ones are:

  • number: Represents numeric values, both integers and floating-point.

    let age: number = 30;
    let price: number = 19.99;
    
    
  • string: Represents sequences of characters.

    let name: string = "Marco";
    let greeting: string = `Hello, ${name}`;
    
    
  • boolean: Represents true or false values.

    let isActive: boolean = true;
    let hasPermission: boolean = false;
    
    
  • null and undefined: Represent the absence of a value.

    let data: null = null;
    let result: undefined = undefined;
    
    
  • any: Lets you opt out of the type system for a specific variable, useful when the type isn’t known ahead of time.

    let dynamicValue: any = "initial value";
    dynamicValue = 42; // No type error
    
    

3.2 Advanced types (unions, intersections)

Beyond primitive types, TypeScript offers advanced types that enable greater flexibility and expressiveness in your code.

  • Unions: Allow a variable to be one of several specified types.

    let id: number | string;
    id = 123; // Valid
    id = "ABC123"; // Also valid
    
    
  • Intersections: Allow you to combine multiple types into one, ensuring the variable has all the properties of the combined types.

    interface Person {
     name: string;
     age: number;
    }
    
    interface Employee {
     employeeId: number;
    }
    
    let employee: Person & Employee = {
     name: "Alice",
     age: 28,
     employeeId: 1001
    };
    
    

3.3 Interfaces and types

Interfaces and types in TypeScript are powerful tools for defining the shape of objects and functions clearly and concisely.

  • Interfaces: Define the structure of objects, specifying their properties and types.

    interface User {
     id: number;
     username: string;
     isAdmin: boolean;
    }
    
    let user: User = {
     id: 1,
     username: "marco_dev",
     isAdmin: true
    };
    
    
  • Types: Similar to interfaces but more versatile, allowing for type composition and manipulation.

    type Point = {
     x: number;
     y: number;
    };
    
    type Circle = {
     radius: number;
    };
    
    type Cylinder = Point & Circle & {
     height: number;
    };
    
    let cylinder: Cylinder = {
     x: 0,
     y: 0,
     radius: 10,
     height: 20
    };
    
    

Interfaces and types are fundamental to making the most of TypeScript’s static type system, providing clarity and robustness to your code.

In short, understanding TypeScript’s basic concepts is essential for starting to write safer, more maintainable code. In the following sections we’ll explore how TypeScript handles classes and objects, functions, modules, and more — giving you everything you need to tap the full potential of this powerful language.

4. Classes and Objects in TypeScript

4.1 Defining classes

TypeScript, as a superset of JavaScript, leverages the object-oriented features introduced in ECMAScript 6 (ES6), such as classes. Classes in TypeScript allow you to define more organized and reusable structures, making it easier to build complex applications.

To define a class in TypeScript, use the class keyword followed by the class name. Inside the class you can define properties, constructors, and methods:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

let person = new Person("Marco", 30);
person.greet(); // Output: Hello, my name is Marco and I am 30 years old.

4.2 Inheritance and polymorphism

TypeScript supports inheritance, allowing classes to extend other classes. This promotes code reuse and the creation of more complex class hierarchies. To extend a class, use the extends keyword:

class Employee extends Person {
  employeeId: number;

  constructor(name: string, age: number, employeeId: number) {
    super(name, age); // Calls the base class constructor
    this.employeeId = employeeId;
  }

  displayEmployeeInfo() {
    console.log(`Employee ID: ${this.employeeId}, Name: ${this.name}, Age: ${this.age}`);
  }
}

let employee = new Employee("Alice", 28, 1001);
employee.displayEmployeeInfo(); // Output: Employee ID: 1001, Name: Alice, Age: 28

Polymorphism in TypeScript is achieved through inheritance and interfaces, allowing different classes to be treated uniformly through a common interface.

4.3 Access modifiers

TypeScript provides access modifiers that control the visibility of a class’s properties and methods. The most common ones are public, private, and protected:

  • public: Properties and methods are accessible from anywhere in the program. This is the default.

    class Car {
     public model: string;
    
     constructor(model: string) {
       this.model = model;
     }
    
     public displayModel() {
       console.log(`Model: ${this.model}`);
     }
    }
    
    let car = new Car("Toyota");
    car.displayModel(); // Output: Model: Toyota
    
    
  • private: Properties and methods are only accessible within the same class.

    class BankAccount {
     private balance: number;
    
     constructor(initialBalance: number) {
       this.balance = initialBalance;
     }
    
     public deposit(amount: number) {
       this.balance += amount;
       console.log(`Deposited: ${amount}, New Balance: ${this.balance}`);
     }
    
     private displayBalance() {
       console.log(`Balance: ${this.balance}`);
     }
    }
    
    let account = new BankAccount(1000);
    account.deposit(500); // Output: Deposited: 500, New Balance: 1500
    // account.displayBalance(); // Error: Property 'displayBalance' is private and only accessible within class 'BankAccount'.
    
    
  • protected: Properties and methods are accessible within the same class and in derived classes.

    class Shape {
     protected color: string;
    
     constructor(color: string) {
       this.color = color;
     }
    }
    
    class Circle extends Shape {
     private radius: number;
    
     constructor(color: string, radius: number) {
       super(color);
       this.radius = radius;
     }
    
     public displayCircleInfo() {
       console.log(`Color: ${this.color}, Radius: ${this.radius}`);
     }
    }
    
    let circle = new Circle("red", 10);
    circle.displayCircleInfo(); // Output: Color: red, Radius: 10
    
    

Understanding and correctly using access modifiers is key to designing robust, secure classes and objects.

In short, classes and objects in TypeScript let you apply object-oriented programming (OOP) principles, making it easier to write more structured, reusable code. The following sections cover typed functions, modules, and the TypeScript tooling ecosystem — giving you a complete picture of how to make the most of this language.

5. Functions and Typing

5.1 Typed functions

In TypeScript, static typing also applies to functions, allowing you to specify the types of parameters and the return type. This helps prevent common mistakes and makes code easier to read and maintain.

function add(a: number, b: number): number {
  return a + b;
}

let result = add(5, 3); // result will have type number

In the example above, a and b are typed as number, and the add function returns a number. If you try to pass arguments of the wrong types, TypeScript will throw a compile-time error.

5.2 Optional and default parameters

TypeScript lets you define optional and default parameters in functions, offering greater flexibility and control over how functions are called.

  • Optional parameters: Indicated by adding a question mark (?) after the parameter name. Optional parameters can be omitted when calling the function.

    function greet(name: string, greeting?: string): string {
     return `${greeting || "Hello"}, ${name}`;
    }
    
    console.log(greet("Marco")); // Output: Hello, Marco
    console.log(greet("Marco", "Hi")); // Output: Hi, Marco
    
    
  • Default parameters: Defined by assigning a default value in the parameter declaration. If no value is provided when calling the function, the default value is used.

    function greet(name: string, greeting: string = "Hello"): string {
     return `${greeting}, ${name}`;
    }
    
    console.log(greet("Marco")); // Output: Hello, Marco
    console.log(greet("Marco", "Hi")); // Output: Hi, Marco
    
    

5.3 Return types

In addition to typing parameters, it’s important to specify a function’s return type. This ensures the function always returns a value of the expected type.

function multiply(a: number, b: number): number {
  return a * b;
}

let product = multiply(4, 5); // product will have type number

If a function doesn’t return any value, use the void type.

function logMessage(message: string): void {
  console.log(message);
}

logMessage("Hello, TypeScript!"); // Output: Hello, TypeScript!

5.4 Functions as types

In TypeScript, functions can also be used as types, allowing you to define variables that store functions with a specific signature.

type MathOperation = (a: number, b: number) => number;

let add: MathOperation = (x, y) => x + y;
let subtract: MathOperation = (x, y) => x - y;

console.log(add(10, 5)); // Output: 15
console.log(subtract(10, 5)); // Output: 5

Defining functions as types is especially useful when working with higher-order functions, where functions are passed as arguments to other functions or returned as results.

5.5 Function overloads

TypeScript supports function overloading, letting you define multiple signatures for the same function implementation. This is useful when a function can accept different combinations of parameters and return different types of results.

function format(input: string): string;
function format(input: number): string;
function format(input: string | number): string {
  if (typeof input === "number") {
    return input.toFixed(2);
  } else {
    return input.toUpperCase();
  }
}

console.log(format(123.456)); // Output: 123.46
console.log(format("hello")); // Output: HELLO

In the example above, the format function has two overload signatures: one that accepts a string and one that accepts a number. The function implementation uses a union type (string | number) and decides how to format the value based on its type.

In short, typed functions are a powerful TypeScript feature that improves code robustness and maintainability. Understanding how to define and use typed functions, optional and default parameters, and function overloads will help you write safer, more efficient code.

6. Module Management

6.1 Importing and exporting modules

TypeScript uses the ECMAScript module system to organize and structure code across separate files. This promotes code reuse and maintainability, especially in large projects.

  • Exporting: To share variables, functions, classes, or interfaces between files, use the export keyword.

    // math.ts
    export function add(a: number, b: number): number {
     return a + b;
    }
    
    export const PI = 3.14;
    
    
  • Importing: To use exported items from another file, use the import keyword.

    // app.ts
    import { add, PI } from './math';
    
    console.log(`PI: ${PI}`);
    console.log(`Add: ${add(5, 3)}`);
    
    

You can also use default exports and imports, which allow a single default export per module.

// user.ts
export default class User {
  constructor(public name: string) {}
}

// app.ts
import User from './user';

let user = new User('Marco');
console.log(user.name); // Output: Marco

6.2 Module configuration in large projects

In large projects it’s common to organize code across multiple directories and modules. To manage this efficiently, TypeScript lets you configure module paths and resolution in tsconfig.json.

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@models/*": ["src/models/*"],
      "@controllers/*": ["src/controllers/*"]
    }
  }
}

In this example, aliases are set up for common paths, simplifying imports:

// src/controllers/userController.ts
import { User } from '@models/user';

export function getUser() {
  return new User('Marco');
}

6.3 Using external modules

TypeScript makes it easy to use external libraries and modules through type declarations. These declarations describe the APIs of libraries and allow TypeScript to verify that they’re used correctly. Type declarations for many popular libraries are available on DefinitelyTyped and can be installed via npm.

npm install --save lodash
npm install --save-dev @types/lodash

Once installed, they can be used in the project with full type support:

import * as _ from 'lodash';

let numbers = [1, 2, 3];
let doubled = _.map(numbers, (num) => num * 2);
console.log(doubled); // Output: [2, 4, 6]

6.4 Dependency management

In TypeScript projects, managing dependencies effectively is crucial. Tools like npm and Yarn let you install, update, and remove packages efficiently. It’s also important to keep package.json and your type declarations in sync to ensure compatibility and avoid conflicts.

{
  "dependencies": {
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "@types/lodash": "^4.14.170",
    "typescript": "^4.3.5"
  }
}

6.5 Compilation and bundling

In large projects, compiling and bundling TypeScript code is handled by tools like Webpack, Rollup, or Parcel. These tools combine multiple files into one, optimizing the application’s performance and load time.

npm install --save-dev webpack webpack-cli ts-loader

Basic Webpack configuration for TypeScript:

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.ts',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

This configuration tells Webpack to use ts-loader to compile TypeScript files and output a single bundle.js file in the dist directory.

In short, module management in TypeScript is essential for organizing and maintaining projects efficiently. Correctly using import/export, path configuration, and bundling tools lets you build scalable, well-structured applications.

7. TypeScript 5.x: features you need to know in 2026

TypeScript 5.0 was a pivotal release in 2023, and between 5.1 and 5.9 (the current version in 2026) a number of features have been added that change the way you write code. If you’re coming from TypeScript 4.x, here’s what you should adopt:

7.1 The satisfies operator

satisfies lets you verify that an object conforms to a type without losing literal inference. It’s the difference between “this is a Config” (you lose exact types) and “this satisfies Config and I still know exactly what each key is.”

type Color = "red" | "green" | "blue";
type Palette = Record<string, Color | [number, number, number]>;

// ❌ With annotation: you lose the specific type of each key
const paletteA: Palette = {
  primary: "red",
  secondary: [255, 0, 0],
};
paletteA.primary.toUpperCase(); // Error: 'string | number[]' has no toUpperCase

// ✅ With satisfies: the type is validated while the literal type is preserved
const paletteB = {
  primary: "red",
  secondary: [255, 0, 0],
} satisfies Palette;

paletteB.primary.toUpperCase(); // OK: TypeScript knows primary is exactly "red"

It’s the go-to tool for configuring objects: route maps, themes, API contracts, validation schemas.

7.2 const type parameters

Const type parameters allow generics to infer literal types without having to write as const at every call site:

function head<const T extends readonly unknown[]>(arr: T): T[0] {
  return arr[0];
}

const first = head(["a", "b", "c"]);
// first is exactly "a", not string

Small, but it eliminates a lot of as const boilerplate.

7.3 Stable decorators (Stage 3)

After years behind the experimentalDecorators flag, decorators are stable as of TypeScript 5.0 and follow the TC39 Stage 3 proposal. And as of TypeScript 5.9, decorator metadata via Symbol.metadata is also stable.

function logged<This, Args extends any[], Return>(
  target: (this: This, ...args: Args) => Return,
  context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>
) {
  return function (this: This, ...args: Args): Return {
    console.log(`Calling ${String(context.name)} with`, args);
    return target.call(this, ...args);
  };
}

class API {
  @logged
  greet(name: string) {
    return `Hello, ${name}`;
  }
}

You no longer need Reflect Metadata or emitDecoratorMetadata for basic use cases.

7.4 using and resource disposal (ES2026)

Inspired by C#‘s using and Python’s with, TypeScript 5.2 introduced using for managing resources that need automatic cleanup:

function getFile() {
  const file = openFile("data.txt");
  return {
    [Symbol.dispose]() {
      file.close();
      console.log("File closed");
    },
    read: () => file.readSync(),
  };
}

{
  using file = getFile();
  console.log(file.read());
} // → "File closed" runs automatically when the block exits

Useful for connections, locks, DB transactions, and file handles — no try/finally needed.

7.5 Awaited<T> and NoInfer<T>

Two modern utility types worth knowing:

type A = Awaited<Promise<Promise<string>>>; // string

function setDefault<T>(value: T, fallback: NoInfer<T>) {
  return value ?? fallback;
}
// NoInfer prevents `fallback` from pulling `value`'s type toward narrowing

7.6 verbatimModuleSyntax and ESM improvements

TypeScript 5+ is much stricter about distinguishing type imports from value imports. Enable verbatimModuleSyntax in your tsconfig.json to avoid surprising behavior with modern bundlers:

{
  "compilerOptions": {
    "verbatimModuleSyntax": true,
    "moduleResolution": "bundler"
  }
}

And always use import type when you only need the type:

import type { User } from './types';

7.7 Improved inference in template literals

type Endpoint = `/${string}`;
type Method = "GET" | "POST" | "PUT" | "DELETE";

function request<E extends Endpoint, M extends Method>(method: M, url: E) {
  // method and url are inferred as exact literals
}

Combined with satisfies, this lets you build fully typed APIs with no extra code.

8. Tools and Ecosystem

7.1 Linters and formatters

Using linting and formatting tools is fundamental to keeping code clean and consistent in any project. The following tools are very popular in the TypeScript ecosystem:

  • ESLint (TSLint was deprecated in 2019): the standard linting tool for TypeScript in 2026. Configure it with the new flat config format and the official typescript-eslint plugin. To get started in a TypeScript project, install ESLint and the necessary plugins:

    npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
    
    

    Then create a .eslintrc.json configuration file:

    {
     "parser": "@typescript-eslint/parser",
     "extends": [
       "eslint:recommended",
       "plugin:@typescript-eslint/recommended"
     ],
     "rules": {
       // Add your custom rules here
     }
    }
    
    
  • Prettier: Prettier is a code formatter that enforces a consistent code style. To integrate it with ESLint, install the following packages:

    npm install prettier eslint-config-prettier eslint-plugin-prettier --save-dev
    
    

    Update .eslintrc.json to include Prettier:

    {
     "parser": "@typescript-eslint/parser",
     "extends": [
       "eslint:recommended",
       "plugin:@typescript-eslint/recommended",
       "plugin:prettier/recommended"
     ],
     "rules": {
       "prettier/prettier": "error"
     }
    }
    
    

7.2 TypeScript-compatible frameworks and libraries

TypeScript works seamlessly with many popular frameworks and libraries, improving the development experience with static typing and autocomplete. Here are some of the most widely used with TypeScript:

  • Angular: Angular is a web development framework that uses TypeScript as its primary language. It provides a robust architecture for building complex, scalable web applications.

    ng new my-angular-app --strict
    
    
  • React: React is a library for building user interfaces that can be used with TypeScript to provide static typing and improve productivity.

    npx create-react-app my-react-app --template typescript
    
    
  • Vue: Vue.js also supports TypeScript, letting developers use static typing and other TypeScript features in their Vue projects.

    vue create my-vue-app
    # Select TypeScript as an option during setup
    
    

7.3 Integration with Node.js

TypeScript is an excellent choice for building server-side applications with Node.js. To get started, configure your project with a tsconfig.json and the required dependencies:

npm init -y
npm install typescript @types/node ts-node --save-dev

Create a tsconfig.json with a basic configuration:

{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}

In package.json, add a script to run the server with ts-node:

{
  "scripts": {
    "start": "ts-node src/index.ts"
  }
}

7.4 Testing with TypeScript

Testing is a crucial part of software development, and TypeScript integrates well with many testing tools. Here are some of the most popular options:

  • Jest: Jest is a testing framework with excellent TypeScript support. To configure it, install Jest and the TypeScript support packages:

    npm install jest @types/jest ts-jest --save-dev
    
    

    Create a jest.config.js configuration file:

    module.exports = {
     preset: 'ts-jest',
     testEnvironment: 'node',
     testMatch: ['**/__tests__/**/*.ts']
    };
    
    
  • Mocha and Chai: Mocha is a flexible testing framework and Chai is an assertion library that can be used alongside it.

    npm install mocha @types/mocha chai @types/chai ts-node --save-dev
    
    

    Add a test script in package.json:

    {
     "scripts": {
       "test": "mocha -r ts-node/register 'src/**/*.spec.ts'"
     }
    }
    
    

7.5 Documentation and type generation

Generating clear, accurate documentation is essential in any project. TypeScript can help with this through automatic documentation generation based on types.

  • TypeDoc: TypeDoc is a tool that generates documentation from TypeScript files. Install and configure it as follows:

    npm install typedoc --save-dev
    
    

    Add a script in package.json:

    {
     "scripts": {
       "doc": "typedoc --out docs src"
     }
    }
    
    

    Run the script to generate the documentation:

    npm run doc
    
    

In short, the TypeScript ecosystem is packed with tools and libraries that improve the development experience, from linters and formatters to frameworks and testing tools. Leveraging these tools can help you write cleaner, more maintainable, and more robust code.

9. Migrating from JavaScript to TypeScript

8.1 Migration strategies

Migrating an existing JavaScript project to TypeScript may seem daunting, but with the right strategy the process can be manageable and very rewarding. Here are some common migration strategies:

  1. Incremental migration: Rather than migrating the entire project at once, migrate it piece by piece. Start with critical parts or specific modules, make sure they work correctly, and then move on to other parts.

  2. Using .ts and .js files together: TypeScript lets you work with both .ts and .js files in the same project. This makes gradual migration easier — you can convert individual files from JavaScript to TypeScript without breaking the rest of the code.

  3. Enable allowJs in tsconfig.json: This option lets you compile JavaScript files alongside TypeScript files, enabling a smooth gradual transition.

    {
     "compilerOptions": {
       "allowJs": true,
       "checkJs": true, // Optional: enable type checking in .js files
       "outDir": "./dist",
       "rootDir": "./src"
     },
     "include": ["src/**/*"]
    }
    
    
  4. Add types gradually: Start with basic types and add more specific ones as you get comfortable with TypeScript. Use any where necessary at first and refine it later.

8.2 Benefits and challenges

Migrating to TypeScript offers many benefits, but also presents some challenges. Understanding both is important for planning the migration properly.

Benefits:

  • Early error detection: TypeScript helps catch errors at compile time, reducing bugs in production.
  • Better maintainability: The type system makes code easier to understand and maintain, especially in large projects.
  • Autocomplete and navigation: Code editors can offer better autocomplete and navigation features, increasing developer productivity.
  • Growing ecosystem: TypeScript is widely adopted by popular frameworks and libraries, making integration with other projects easier.

Challenges:

  • Learning curve: Developers need to learn TypeScript’s features and syntax, which takes time.
  • Initial setup: Correctly configuring TypeScript for an existing project can be complex, especially for large, intricate codebases.
  • Compatibility issues: Some libraries or tools may not have full TypeScript support, which can require workarounds or additional configuration.

8.3 Practical examples

Here are some practical examples to illustrate the migration process from JavaScript to TypeScript:

Example 1: Migrating a simple function

JavaScript:

function greet(name) {
  return "Hello, " + name;
}

TypeScript:

function greet(name: string): string {
  return `Hello, ${name}`;
}

Example 2: Migrating a complex object

JavaScript:

const user = {
  id: 1,
  name: "Marco",
  isAdmin: true
};

TypeScript:

interface User {
  id: number;
  name: string;
  isAdmin: boolean;
}

const user: User = {
  id: 1,
  name: "Marco",
  isAdmin: true
};

Example 3: Migrating a module with exports and imports

JavaScript:

// math.js
export function add(a, b) {
  return a + b;
}

// app.js
import { add } from './math';
console.log(add(2, 3));

TypeScript:

// math.ts
export function add(a: number, b: number): number {
  return a + b;
}

// app.ts
import { add } from './math';
console.log(add(2, 3));

8.4 Useful migration tools

Several tools can make the migration to TypeScript easier:

  • ts-migrate: A tool that automates much of the initial migration work.

    npx ts-migrate-full <project-root>
    
    
  • Type definitions: Type packages for popular projects, available on DefinitelyTyped.

    npm install @types/lodash --save-dev
    
    
  • TypeScript ESLint: ESLint integration with TypeScript to keep code clean during and after the migration.

    npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser --save-dev
    
    

In short, migrating a project from JavaScript to TypeScript is a process that can yield great benefits in terms of code quality and maintainability. Adopting an incremental migration strategy and using the right tools makes the process smoother and more effective.

10. Best Practices

9.1 Effective use of types

Using types effectively in TypeScript is essential for getting the most out of its capabilities and ensuring robust, maintainable code. Here are some best practices for working with types in TypeScript:

  • Explicit typing: Whenever possible, use explicit types rather than relying on type inference. This makes code clearer and easier to understand.

    // Better
    let age: number = 30;
    // Acceptable, but less clear
    let age = 30;
    
    
  • Avoid any: Although the any type is useful in some situations, its use should be minimized since it disables TypeScript’s type system, eliminating many of the benefits it provides.

    // Better
    function add(a: number, b: number): number {
     return a + b;
    }
    // Avoid
    function add(a: any, b: any): any {
     return a + b;
    }
    
    
  • Use custom types: Define custom types and use interfaces or type aliases to represent complex data structures.

    interface User {
     id: number;
     name: string;
     isAdmin: boolean;
    }
    
    let user: User = {
     id: 1,
     name: "Marco",
     isAdmin: true
    };
    
    
  • Use union and intersection types: Union and intersection types allow for more flexible typing, providing more robust type definitions.

    type Result = Success | Failure;
    
    interface Success {
     success: true;
     data: any;
    }
    
    interface Failure {
     success: false;
     error: string;
    }
    
    function processResult(result: Result) {
     if (result.success) {
       console.log(result.data);
     } else {
       console.error(result.error);
     }
    }
    
    

9.2 Documentation and comments

Documentation and comments are essential for maintaining understandable, maintainable code — especially in large, collaborative projects.

  • JSDoc comments: Use JSDoc comments to document functions, classes, and properties. This provides useful information to developers and improves the autocomplete experience in code editors.

    /**
    * Adds two numbers together.
    * @param a - The first number.
    * @param b - The second number.
    * @returns The sum of `a` and `b`.
    */
    function add(a: number, b: number): number {
     return a + b;
    }
    
    
  • Implementation comments: Use comments inside functions and methods to explain complex or unusual logic. This helps other developers (and your future self) quickly understand the purpose of the code.

    function calculateDiscount(price: number, discount: number): number {
     // Make sure the discount is not negative
     if (discount < 0) {
       throw new Error("Discount cannot be negative");
     }
     return price - (price * discount);
    }
    
    

9.3 Testing with TypeScript

Writing tests for your code is an essential practice for ensuring its quality and reliability. TypeScript integrates well with many testing tools, making it easy to write typed tests.

  • Configure Jest for TypeScript: Jest is a popular testing framework that can be configured to work with TypeScript.

    npm install jest ts-jest @types/jest --save-dev
    
    

    Create a jest.config.js configuration file:

    module.exports = {
     preset: 'ts-jest',
     testEnvironment: 'node',
     testMatch: ['**/__tests__/**/*.ts']
    };
    
    
  • Write unit tests: Make sure to write unit tests for your functions and methods. This helps catch errors quickly and ensures code behaves as expected.

    // math.ts
    export function add(a: number, b: number): number {
     return a + b;
    }
    
    // math.test.ts
    import { add } from './math';
    
    test('adds 1 + 2 to equal 3', () => {
     expect(add(1, 2)).toBe(3);
    });
    
    

9.4 Keep code clean and organized

Keeping code clean and organized is crucial for long-term maintainability. Here are some recommended practices:

  • Follow a naming convention: Use a consistent naming convention for variables, functions, classes, and files. This improves readability and makes navigating the code easier.

  • Split code into modules: Organize your code into separate modules, each with a clear responsibility. This makes the codebase easier to manage and maintain.

    // src/utils/math.ts
    export function add(a: number, b: number): number {
     return a + b;
    }
    
    // src/index.ts
    import { add } from './utils/math';
    console.log(add(1, 2));
    
    
  • Avoid code duplication: Reuse functions and modules as much as possible to avoid duplicating code. This reduces the risk of bugs and makes updating the codebase easier.

  • Review and refactor regularly: Review and refactor code regularly to improve its quality and eliminate accumulated technical debt.

In short, following best practices for types, documentation, testing, and code organization is essential for getting the most out of TypeScript’s capabilities and ensuring robust, maintainable code. Adopting these practices will help you write high-quality code that is easy to understand, test, and maintain over the long term.

11. Conclusion

10.1 Summary of key points

Throughout this article, we’ve explored various aspects of TypeScript, a typed superset of JavaScript that improves code robustness and maintainability. Here’s a summary of the key points we covered:

  • Introduction to TypeScript: We defined what TypeScript is, its history and evolution, and the importance of static typing for catching errors at compile time and improving developer productivity.
  • Installation and Configuration: We walked through how to install TypeScript, configure the compiler via tsconfig.json, and integrate TypeScript with popular code editors like VSCode and Sublime Text.
  • TypeScript Basics: We covered primitive types, advanced types like unions and intersections, and how to use interfaces and types to define clear and concise data structures.
  • Classes and Objects: We explored class definitions, inheritance, polymorphism, and access modifiers like public, private, and protected for controlling the visibility of properties and methods.
  • Functions and Typing: We explained how to define typed functions, use optional and default parameters, specify return types, and work with function overloads.
  • Module Management: We covered how to import and export modules, configure paths in large projects, use external modules, and manage dependencies efficiently.
  • Tools and Ecosystem: We looked at linting and formatting tools like ESLint and Prettier, TypeScript-compatible frameworks such as Angular, React, and Vue, and integration with Node.js and testing tools.
  • Migrating from JavaScript to TypeScript: We discussed migration strategies, benefits and challenges, practical examples, and useful tools to facilitate the transition.
  • Best Practices: We emphasized the importance of effective type usage, documentation and comments, testing, and keeping code clean and organized.

10.2 Additional resources for learning TypeScript

To continue deepening your TypeScript knowledge, here are some additional resources that can help you improve your skills:

  • Official TypeScript documentation: The official docs are the most complete and up-to-date resource for learning TypeScript. You can find them at TypeScript Lang.

  • Books:

    • Programming TypeScript by Boris Cherny: A detailed book covering TypeScript from the basics to advanced concepts.
    • TypeScript Quickly by Yakov Fain and Anton Moiseev: A practical, fast-paced guide to learning TypeScript.
  • Online courses:

  • Tutorials and guides:

10.3 The future of TypeScript in web development

TypeScript has proven itself to be a valuable tool for building modern applications, and its popularity continues to grow. With Microsoft’s backing and adoption by major companies and open-source projects, TypeScript’s future looks very bright. Some trends to watch include:

  • Greater adoption in open-source projects: More and more open-source projects are adopting TypeScript, making it easier for developers worldwide to collaborate and contribute.
  • Integration with new technologies: As new technologies and frameworks emerge, TypeScript will likely integrate with them to provide more robust, safer development experiences.
  • Tooling ecosystem improvements: New tools will continue to be developed and existing ones improved to make TypeScript development even more efficient and enjoyable.

In short, TypeScript is a powerful tool that significantly improves the quality and maintainability of code in projects of any size. By adopting TypeScript and following best practices, you can build more robust, secure, and maintainable applications.

12. References and Additional Resources

11.1 Official documentation

The official TypeScript documentation is the most complete and up-to-date resource for learning and deepening your knowledge of TypeScript. Here you’ll find guides, tutorials, examples, and detailed references covering all language features.

  • TypeScript Handbook: Handbook
  • API Reference: API
  • Playground: Playground - An interactive environment for trying out TypeScript code online.

The following books offer a detailed and practical look at TypeScript, from basics to advanced topics, and are valuable resources for developers who want to master the language:

  • Programming TypeScript by Boris Cherny: This book provides comprehensive coverage of TypeScript, from basic concepts to advanced practices, with practical examples and detailed explanations.
  • TypeScript Quickly by Yakov Fain and Anton Moiseev: A practical guide to learning TypeScript quickly, with numerous examples and real-world use cases.
  • Learning TypeScript by Josh Goldberg: Ideal for beginners, this book covers all the fundamental aspects of TypeScript with a friendly and accessible approach.

11.3 Online courses and tutorials

There are many online courses and tutorials that can help you learn and sharpen your TypeScript skills. Here are some recommendations:

  • TypeScript Fundamentals on Pluralsight: A detailed course covering the fundamentals of TypeScript and helping you start using the language effectively.
  • Understanding TypeScript on Udemy: A comprehensive course spanning basic to advanced TypeScript concepts, with practical examples and exercises.
  • TypeScript for Professionals on LinkedIn Learning: A course aimed at experienced JavaScript developers who want to learn TypeScript to improve their workflow.

11.4 Blogs and articles

Blogs and articles are a great way to stay up to date with the latest TypeScript trends and practices. Here are some blogs and online resources worth following:

  • TypeScript Deep Dive by Basarat Ali Syed: A free online book offering a deep dive into TypeScript with examples and detailed explanations.
  • The TypeScript Blog: The official TypeScript blog, where you can find release announcements, technical articles, and case studies. TypeScript Blog
  • 2ality: A blog by Axel Rauschmayer offering detailed articles on JavaScript and TypeScript, covering a wide range of topics and use cases. 2ality

11.5 Communities and forums

Participating in online communities and forums can be very helpful for resolving doubts, sharing knowledge, and learning from other developers. Here are some active communities:

  • Stack Overflow: A popular forum where you can ask questions and get answers from the developer community. Stack Overflow TypeScript
  • TypeScript Reddit: A subreddit dedicated to TypeScript where you can find news, discussions, and useful resources. r/typescript
  • GitHub Discussions: The TypeScript community on GitHub where you can participate in discussions, report issues, and contribute to the language’s development. TypeScript GitHub Discussions

11.6 Tools and extensions

To improve your TypeScript workflow, consider using some of the following tools and extensions:

  • Visual Studio Code (VSCode): A highly recommended editor for working with TypeScript, with native support and many useful extensions.
    • TypeScript ESLint: An extension to integrate ESLint with TypeScript, helping you keep your code clean and error-free.
    • Prettier: A code formatter that enforces a consistent style throughout your project.
  • TypeDoc: A tool for generating documentation from TypeScript code. TypeDoc
  • Webpack: A module bundler that can be configured to work with TypeScript, making large project management easier. Webpack

In short, there are many resources available to learn and improve your TypeScript skills — from official documentation and books to online courses, blogs, communities, and tools. Taking advantage of these resources will help you master TypeScript and write more robust, maintainable, and efficient code.

Compartir

Search

Tags