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:
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
interfacedeclaration is completely removed in the JavaScript output. TypeScript interfaces are a compile-time construct and have no runtime representation. - Type annotations (like
: Userand: 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
Local Installation (Recommended)
For most projects, it’s recommended to install TypeScript locally within your project:
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:
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):
Using yarn:
Using bun (ultra-fast JavaScript runtime):
Verify Installation
After installation, you can check the installed version of TypeScript by running:
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:
This will:
- Create a new project directory
- Initialize a
package.jsonfile- You might want to edit the
package.jsonto add a"type": "module"field if you plan to use ES modules.
- You might want to edit the
- Install TypeScript locally
- Generate a comprehensive
tsconfig.jsonfile 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:
Add code
Now - add a helloworld.ts in the root of your folder:
and a index.ts
Transpile and execute TS
Now you should be able to run from a terminal by executing:
Modern Alternative
For a faster development experience, you can use tsx to run TypeScript directly:
It should print
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:
For development purposes, you can set it to allow local scripts:
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:
then changehelloworld.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
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:
Both tsx and ts-node can be run directly with npx without installation, or installed locally for faster subsequent runs:
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.