TypeScript Programming
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. It adds static typing to help identify potential errors during development rather than at runtime. This guide covers the core concepts of TypeScript, from basic setup to intermediate features.
1. Introduction and Setup
TypeScript does not run directly in the browser or in Node.js. It must first be compiled (transpiled) into standard JavaScript.
Installation
To install TypeScript globally on your system using npm (Node Package Manager), run:
npm install -g typescript
Compiling Your First File
Create a file named index.ts and add the following code:
const message: string = "Hello, TypeScript";
console.log(message);
To compile this file into JavaScript, run the TypeScript compiler (tsc):
tsc index.ts
This command generates an index.js file in the same directory, which can be executed by Node.js or loaded in a browser.
Initialization and Configuration
For larger projects, a configuration file named tsconfig.json is used to manage compiler options. Generate this file by running:
tsc --init
Key options in tsconfig.json include:
-
target: The version of JavaScript to output (e.g.,ES6,ES2020). -
module: The module resolution system (e.g.,CommonJS,ESNext). -
strict: Enables a wide range of type-checking behaviors to ensure type safety. -
outDir: The directory where compiled JavaScript files will be placed.
2. Basic Types
TypeScript provides several basic types to describe the shape of your data.
Primitives
let isCompleted: boolean = false;
let decimal: number = 6;
let color: string = "blue";
Arrays
Arrays can be defined in one of two equivalent ways:
// Using type[]
let list: number[] = [1, 2, 3];
// Using Generic Array Type
let genericList: Array<number> = [1, 2, 3];
Tuples
Tuples allow you to express an array with a fixed number of elements whose types are known, but need not be the same.
let address: [string, number];
address = ["Main Street", 123]; // Correct
// address = [123, "Main Street"]; // Error: Type 'number' is not assignable to type 'string'
Enums
Enums allow you to define a set of named constants. By default, enums begin numbering their members starting at 0.
enum Direction {
Up = 1, // Custom start index
Down, // 2
Left, // 3
Right, // 4
}
let dir: Direction = Direction.Up;
Any and Unknown
-
any: Opts out of type-checking. It allows any operations or properties to be accessed. Use it sparingly, as it bypasses the benefits of TypeScript. -
unknown: A type-safe counterpart toany. Anything is assignable tounknown, but you cannot perform operations on anunknownvariable without first narrowing its type (e.g., via type guards).
let value: unknown = "Hello World";
// console.log(value.toUpperCase()); // Error: Object is of type 'unknown'
if (typeof value === "string") {
console.log(value.toUpperCase()); // Allowed because type is narrowed to 'string'
}
Void and Never
-
void: Commonly used as the return type of functions that do not return a value. -
never: Represents the type of values that never occur (e.g., a function that always throws an exception or one that enters an infinite loop).
function logMessage(message: string): void {
console.log(message);
}
function throwError(message: string): never {
throw new Error(message);
}
3. Type Inference and Type Annotations
TypeScript attempts to infer types automatically when no explicit annotation is provided.
let x = 3; // TypeScript infers 'x' is of type 'number'
// x = "hello"; // Error: Type 'string' is not assignable to type 'number'
While type inference is useful, explicit type annotations are beneficial for:
1. Declaring function signatures (parameters and return values).
2. Ensuring variables do not implicitly fall back to the any type when declared without an initial value.
4. Interfaces and Type Aliases
Both interfaces and type aliases allow you to define the shape of an object, but they have subtle differences.
Interfaces
Interfaces are primarily used to define object shapes and can be extended.
interface User {
readonly id: number; // Cannot be modified after initialization
username: string;
email?: string; // Optional property
}
const user1: User = {
id: 1,
username: "alice",
};
Type Aliases
Type aliases can represent primitive types, unions, tuples, and intersections, in addition to object shapes.
type ID = string | number;
type Point = {
x: number;
y: number;
};
Differences
- Extending: Interfaces use
extendsto inherit properties, while Type Aliases use intersection operators (&). - Declaration Merging: You can declare an interface multiple times, and the compiler will merge them. Type aliases cannot be changed once declared.
// Interface declaration merging
interface Window {
title: string;
}
interface Window {
ts: string;
}
// Window now has both 'title' and 'ts' properties
5. Functions
Functions in TypeScript allow you to annotate both the parameters and the return value.
function add(x: number, y: number): number {
return x + y;
}
Optional and Default Parameters
- Optional Parameters: Marked with a
?and must come after required parameters. - Default Parameters: Assigned a default value if none is provided.
function greet(name: string, greeting: string = "Hello", title?: string): string {
if (title) {
return `${greeting}, ${title} ${name}`;
}
return `${greeting}, ${name}`;
}
6. Classes
TypeScript supports object-oriented programming with classes, including inheritance and access modifiers.
Access Modifiers
-
public(default): Accessible from anywhere. -
private: Accessible only within the class. -
protected: Accessible within the class and its subclasses. -
readonly: Properties must be initialized at their declaration or in the constructor.
class Employee {
public name: string;
private salary: number;
protected department: string;
constructor(name: string, salary: number, department: string) {
this.name = name;
this.salary = salary;
this.department = department;
}
public getDetails(): string {
return `${this.name} works in ${this.department}.`;
}
}
Parameter Properties
You can declare and initialize properties directly within the constructor arguments as a shorthand:
class SimpleEmployee {
constructor(public name: string, private salary: number) {}
}
7. Generics
Generics enable you to write reusable code that can work with a variety of types while maintaining type safety.
Generic Functions
function identity<T>(arg: T): T {
return arg;
}
let output1 = identity<string>("myString");
let output2 = identity<number>(100);
Generic Interfaces
interface KeyValuePairs<K, V> {
key: K;
value: V;
}
const item: KeyValuePairs<string, number> = { key: "age", value: 30 };
8. Unions, Intersections, and Type Guards
TypeScript provides mechanisms for combining and working with multiple types.
Union Types
A union type describes a value that can be one of several types.
function formatInput(input: string | number) {
if (typeof input === "string") {
return input.trim();
}
return input.toFixed(2);
}
Intersection Types
An intersection type combines multiple types into one, requiring the value to satisfy all combined types.
interface Detailed {
description: string;
}
interface Priced {
price: number;
}
type Product = Detailed & Priced;
const book: Product = {
description: "A great book",
price: 19.99,
};
Type Assertions
If you know more about a value's type than TypeScript can infer, you can use a type assertion to treat the value as a specific type.
let someValue: unknown = "This is a string";
// Use 'as' syntax
let strLength: number = (someValue as string).length;
The guide was created in June 2026.