Skip to content

Introduction to TypeScript

TypeScript was introduced by Microsoft in October 2012 as a free and open-source programming language. Anders Hejlsberg, the lead architect of C# and creator of Delphi and Turbo Pascal, played a significant role in its development. TypeScript was born out of the need to address the growing challenges in managing large-scale JavaScript applications.

TS is Open Source - se https://github.com/Microsoft/TypeScript

TypeScript Version History
Version Year Highlights
1.0 2014 Initial release of TypeScript. Introduced static typing to JavaScript.
1.1 2014 Performance improvements and better integration with Visual Studio.
1.2 2014 Introduction of Enums and improved generics.
1.3 2014 Support for ‘protected’ modifier and tuple types.
1.4 2015 Union types, type aliases, and ES6 template strings.
1.5 2015 Support for ES6 modules, decorators, and a new tsconfig.json configuration file.
1.6 2015 Introduction of JSX support, abstract classes, and module resolution enhancements.
1.7 2015 Support for async/await (for ES6 targets) and polymorphic this typing.
1.8 2016 Control flow based type analysis, string literal types, and JSX spread attributes.
1.9 2016 Keyof type operator, readonly properties, and module augmentation.
2.0 2016 Introduction of non-nullable types, control flow based type guards, and tagged union types.
2.1 2016 Key-value type mapping, partial types, and easier imports.
2.2 2017 Mixin classes, object type, and improved string indexing behavior.
2.3 2017 Async iterators and generators, and downlevel generator support.
2.4 2017 Dynamic import expressions, string enums, and stricter checks.
2.5 2017 Optional catch clause variables and improved refactoring.
2.6 2017 Strict function types and localized diagnostic messages.
2.7 2018 Definite assignment assertions and easier ES module interoperability.
2.8 2018 Conditional types and improved type inference.
2.9 2018 Symbol-based API for object spread and rest, and richer tuple types.
3.0 2018 Project references, richer tuple types, and new unknown top type.
3.1 2018 Mappable tuple and array types, and property assignments in JS functions.
3.2 2018 BigInt support and improved narrowing for tagged unions.
3.3 2019 Improved speed, better behavior for calling union types, and incremental builds.
3.4 2019 Faster incremental builds, higher order type inference from generic functions.
3.5 2019 Improved excess property checks, type-checking speed improvements.
3.6 2019 Stricter generators, improved UX around promises, and more accurate array spread.
3.7 2019 Optional chaining, nullish coalescing, and assertion functions.
3.8 2020 Type-only imports and exports, and ECMAScript private fields.
3.9 2020 Speed improvements, @ts-expect-error comments.
4.0 2020 Variadic tuple types, labeled tuple elements, and class property inference from constructors.
4.1 2020 Template literal types, key remapping in mapped types.
4.2 2021 Leading/middle rest elements in tuple types, stricter checks for the in operator.
4.3 2021 Separate write types on properties, override and the --noImplicitOverride flag.
4.4 2021 Control flow analysis of aliased conditions and discriminants, symbol and template string pattern template types.
4.5 2021 Type and Promise Improvements
4.6 2022 Allowing Code in Constructors Before super()
4.7 2022 ECMAScript Module Support in Node.js
4.8 2022 Improved Intersection Reduction, Union Compatibility, and Narrowing
4.9 2022 The satisfies Operator
5.0 2023 Decorators
5.1 2023 Namespaced JSX Attributes and unrelated types for getters and setters
5.2 2023 Using declarations, unnamed tuple elements, and easier method usage
5.3 2023 Import attributes, resolution customization, and switch (true) narrowing
5.4 2024 NoInfer utility type, auto-accessors in classes, and conditional type constraints
5.5 2024 Inferred type predicates, control flow narrowing, and JSDoc @import tag
5.6 2024 Iterator helper methods, disallowed nullish coalescing, and improved performance
5.7 2024 Path mapping preservation, relative type-only imports, and better error messages
5.8 2025 Improved type inference, better module resolution, and performance enhancements
5.9 2025 Enhanced control flow analysis, stricter checks, and tooling improvements

Note: The above table provides a high-level overview of TypeScript’s version history. Some minor releases and specific features might not be included.

What is TypeScript?

TypeScript is a superset of JavaScript, which means that all valid JavaScript code is also valid TypeScript code. However, TypeScript brings static typing to the table, allowing developers to define types for their variables, functions, and properties. This type system helps catch errors at compile-time rather than runtime, leading to more robust and maintainable codebases.

What is static typing

Static typing refers to a programming language feature where variable types are determined at compile-time, rather than at runtime. This means that the type of a variable is defined when the code is written and, importantly, checked before the code is executed.

Benefits of Static Typing:

  • Error Detection: Catch type-related errors early, during the compilation process, rather than facing unexpected behaviors at runtime.
  • Performance: Some statically-typed languages can be optimized more aggressively by compilers, leading to faster execution.
  • Readability: Type annotations can make code more self-documenting, helping developers understand the structure and intent of the code.
  • Refactoring: With static types, tools can provide powerful refactoring capabilities, making it safer and easier to change code.

Example in TypeScript:

let count: number = 10;  // `count` is explicitly typed as a number

Why TypeScript?

  • Static Typing: Catching errors early in the development process can save a lot of time and reduce bugs.
  • Enhanced IDE Support: With TypeScript, IDEs provide better autocompletion, navigation, and refactoring capabilities.
  • Scalability: TypeScript is designed to build large-scale applications, making it easier to manage and refactor code.
  • ESNext Features: TypeScript supports newer ECMAScript features, allowing developers to use the latest JavaScript functionalities while ensuring compatibility with older browsers.

Popularity Today

Over the years, TypeScript’s popularity has surged. Many large corporations and projects have adopted TypeScript for their development, including Angular, Vue.js, and even the Babel compiler. According to various developer surveys, TypeScript ranks as one of the top languages developers want to learn and use.

JSDoc Trend

There is a trend in the JavaScript community where some companies are moving away from TS to use JSDoc instead. Some developers and teams prefer to use JSDoc annotations for type checking because it allows them to stay within the JavaScript ecosystem without the need for a separate compilation step. This can be especially appealing for smaller projects or projects where the overhead of setting up and maintaining a TypeScript configuration is deemed unnecessary. However, for larger projects or projects where strong type guarantees are essential, TypeScript’s more robust type system and tooling support can be invaluable. As a result, many companies and projects continue to adopt and use TypeScript. It’s also worth noting that some projects use a combination of both: they might use TypeScript for parts of the codebase and JSDoc annotations for other parts.

Where Can It Be Used?

TypeScript can be used anywhere JavaScript can. This includes:

  • Front-end Development: With frameworks like Angular, React, and Vue.js.

  • Back-end Development: Using Node.js with frameworks like Express.js or Nest.js.

  • Mobile App Development: With frameworks like React Native or NativeScript.

  • Game Development: Using platforms like Phaser or Babylon.js.

  • Desktop Applications: Using frameworks like Electron.

Simple example

Let’s take a simple TypeScript example that showcases some of its unique features, and then see how it gets transpiled into JavaScript.

TypeScript Code

// Define an interface for a user
interface User {
    id: number;
    name: string;
}

// Create a function that takes a user and returns a greeting
function greetUser(user: User): string {
    return `Hello, ${user.name}! Your ID is ${user.id}.`;
}

// Use the function
const user: User = { id: 1, name: "Alice" };
console.log(greetUser(user));

When the above TypeScript code is transpiled using the TypeScript compiler (tsc), it gets converted into the following JavaScript code:

JavaScript Code

Here is the code after transpilation:

// Create a function that takes a user and returns a greeting
function greetUser(user) {
    return "Hello, " + user.name + "! Your ID is " + user.id + ".";
}

// Use the function
var user = { id: 1, name: "Alice" };
console.log(greetUser(user));

Observations

  • The interface declaration is completely removed in the JavaScript output. TypeScript interfaces are a compile-time construct and have no runtime representation.
  • Type annotations (like : User and : string) are also removed, as JavaScript doesn’t have static typing.
  • The rest of the code remains largely unchanged, as the logic itself is the same in both TypeScript and JavaScript.

This example demonstrates how TypeScript adds a layer of type safety without altering the underlying logic of the JavaScript code.

Transpilation vs. Compilation

What is Transpilation? Transpilation is the process of converting source code from one language or version to another language or version that is at a similar level of abstraction. The output is not machine code but rather source code in another high-level language. A common use case is converting newer versions of a language to older ones for broader compatibility, such as converting ES6 JavaScript to ES5.

What is Compilation? Compilation is the process of converting source code written in a high-level programming language into machine code or bytecode. This output can be directly executed by a computer’s CPU or run on a virtual machine, respectively.

Why is TypeScript Transpiled and Not Compiled? - Same Level of Abstraction: TypeScript is a superset of JavaScript. When TypeScript is transpiled, it’s converted to JavaScript, which is at the same level of abstraction. There’s no machine code or bytecode generation involved.

  • Browser Compatibility: Web browsers understand and execute JavaScript. By transpiling TypeScript to JavaScript, developers can ensure that their TypeScript code can run in any environment where JavaScript runs.

  • Flexibility: Transpilation allows developers to target specific versions of JavaScript, ensuring compatibility with older browsers or environments. For instance, TypeScript can be transpiled to ES5, ES6, or newer versions of JavaScript based on the developer’s requirements.

In Summary: While the terms “transpilation” and “compilation” are sometimes used interchangeably, they serve different purposes. TypeScript is transpiled to JavaScript to maintain compatibility and flexibility across various environments without diving into lower-level machine code.

How to Install TypeScript

Installing TypeScript can be done in several ways, with different approaches recommended for different use cases. Here are the most common and recommended methods:

Node.js and npm

Before you can install TypeScript, you need to have Node.js and a package manager installed on your computer. I recommend using Node.js LTS version:

  • Download and install Node.js, which comes with npm.

Tip

Instead of starting from scratch, you can also download my starter template from https://github.com/devcronberg/my-ts-project

For most projects, it’s recommended to install TypeScript locally within your project:

npm install --save-dev typescript

This approach ensures that:

  • Different projects can use different TypeScript versions
  • Your project dependencies are clearly defined
  • Team members get the same TypeScript version

Global Installation

If you want to use TypeScript across multiple projects or for quick experiments, you can install it globally:

npm install -g typescript

Global Installation Considerations

While global installation is convenient, it can lead to version conflicts between projects. I recommend using local installations for production projects.

Alternative Package Managers

You can also use modern package managers:

Using pnpm (faster, disk-efficient):

pnpm add -D typescript

Using yarn:

yarn add --dev typescript

Using bun (ultra-fast JavaScript runtime):

bun add -d typescript

Verify Installation

After installation, you can check the installed version of TypeScript by running:

tsc --version
This command should display the version number, confirming that TypeScript was installed successfully.

Getting Started

If you’re starting a new TypeScript project, here’s the modern recommended approach:

mkdir my-ts-project
cd my-ts-project
npm init -y
npm install --save-dev typescript
npx tsc --init

This will:

  1. Create a new project directory
  2. Initialize a package.json file
    1. You might want to edit the package.json to add a "type": "module" field if you plan to use ES modules.
  3. Install TypeScript locally
  4. Generate a comprehensive tsconfig.json file with recommended defaults

ES Modules Support

If you’re using ES modules (with "module": "ESNext" in tsconfig.json), add "type": "module" to your package.json:

{
  "type": "module",
  "devDependencies": {
    "typescript": "^5.9.0"
  }
}

Add code

Now - add a helloworld.ts in the root of your folder:

export function printHelloWorld(name: string): void {
    console.log(`Hello World - ${name}`);
}

and a index.ts

import { printHelloWorld } from "./helloworld.js";
printHelloWorld("test");

Transpile and execute TS

Now you should be able to run from a terminal by executing:

npx tsc
node ./dist/index.js

Modern Alternative

For a faster development experience, you can use tsx to run TypeScript directly:

npx tsx index.ts

It should print

Hello World - test

Use VSC/Debugging

If you want to debug through Visual Studio Code, add a .vscode folder and in that a launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "program": "${workspaceFolder}/dist/index.js",
            "preLaunchTask": "tsc: build - tsconfig.json",
            "outFiles": [
                "${workspaceFolder}/dist/**/*.js"
            ],
            "console": "integratedTerminal"
        }
    ]
}

and a tasks.json:

{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "typescript",
            "tsconfig": "tsconfig.json",
            "option": "watch",
            "problemMatcher": [
                "$tsc-watch"
            ],
            "group": "build",
            "label": "tsc: watch - tsconfig.json"
        },
        {
            "type": "typescript",
            "tsconfig": "tsconfig.json",
            "problemMatcher": [
                "$tsc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "label": "tsc: build - tsconfig.json"
        }
    ]
}

Tip

then you can debug with F5 and run without debugger with Ctrl+F5.

PowerShell Execution Policy

If you have problems running the transpiler with F5 on Windows, it could be due to security restrictions. You can check your current execution policy with:

Get-ExecutionPolicy

For development purposes, you can set it to allow local scripts:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

This is safer than Unrestricted and only affects the current user. Always follow your organization’s security policies.

Use external package

If you want to add a library like lodash:

npm install lodash-es
npm install --save-dev @types/lodash-es
then change helloworld.ts to:

import { capitalize } from "lodash-es";

export function printHelloWorld(name: string): void {
    console.log(`Hello World - ${capitalize(name)}`);
}

and execute (F5) again. It should now print

Hello World - Test

Alternative: ts-node

Another popular option for running TypeScript directly is ts-node. While tsx is faster (uses esbuild), ts-node is more established and widely used:

npx ts-node index.ts

Both tsx and ts-node can be run directly with npx without installation, or installed locally for faster subsequent runs:

npm install --save-dev ts-node

tsx vs ts-node: - tsx - Faster execution, modern, uses esbuild - ts-node - More mature, better TypeScript compatibility, more configuration options

Choose tsx for speed or ts-node for maximum compatibility and control.