What is TypeScript?
TypeScript is a strongly typed superset of JavaScript that compiles to plain JavaScript. It adds optional static typing, classes, and interfaces to help you build robust applications.
Static Typing
Catch errors at compile time instead of runtime. Type checking helps prevent bugs before they happen.
JavaScript Compatible
Any valid JavaScript is valid TypeScript. Migrate incrementally at your own pace.
Modern Features
Use the latest ECMAScript features and compile down to older JavaScript versions.
Great Tooling
Excellent IDE support with IntelliSense, refactoring, and auto-completion everywhere.
Basics
Type Annotations
// Variable annotations let name: string = "Alice"; let age: number = 30; let isActive: boolean = true; // Type inference (TypeScript infers the type) let message = "Hello"; // inferred as string let count = 42; // inferred as number // Arrays let numbers: number[] = [1, 2, 3]; let names: Array<string> = ["Alice", "Bob"]; // Const (immutable reference) const PI: number = 3.14159;
Type Assertion
// as syntax (preferred) let value: unknown = "hello"; let length: number = (value as string).length; // angle-bracket syntax let length2: number = <string>value.length; // Non-null assertion (use with caution) let element = document.getElementById("myId")!;
Any vs Unknown
// any: opt-out of type checking (avoid when possible) let anything: any = 42; anything = "now a string"; anything.nonExistentMethod(); // no error! // unknown: type-safe any (prefer this) let value: unknown = 42; // value.toFixed(); // Error: must check type first if (typeof value === "number") { value.toFixed(2); // OK }
Types
Primitive Types
| Type | Description | Example |
|---|---|---|
string |
Text values | "hello", 'world', `template` |
number |
Integers and floats | 42, 3.14, NaN, Infinity |
boolean |
True or false | true, false |
null |
Intentional absence | null |
undefined |
Uninitialized value | undefined |
symbol |
Unique identifier | Symbol("id") |
bigint |
Large integers | 100n |
Special Types
// void: no return value function log(message: string): void { console.log(message); } // never: function never returns function throwError(message: string): never { throw new Error(message); } // object: any non-primitive type let obj: object = { name: "Alice" };
Tuples & Enums
// Tuple: fixed-length array with known types let tuple: [string, number] = ["Alice", 30]; let first = tuple[0]; // string let second = tuple[1]; // number // Optional tuple elements let optional: [string, number?] = ["Bob"]; // Enum: named constants enum Direction { Up, // 0 Down, // 1 Left, // 2 Right // 3 } // String enum enum Status { Active = "ACTIVE", Inactive = "INACTIVE", Pending = "PENDING" } let dir: Direction = Direction.Up; let status: Status = Status.Active;
Literal Types
// String literals let alignment: "left" | "center" | "right" = "center"; // Numeric literals let dice: 1 | 2 | 3 | 4 | 5 | 6 = 3; // Boolean literal let isTrue: true = true;
Interfaces & Types
Interfaces
// Basic interface interface User { name: string; age: number; email?: string; // optional property readonly id: number; // readonly property } let user: User = { name: "Alice", age: 30, id: 1 }; // user.id = 2; // Error: readonly // Index signatures interface StringMap { [key: string]: string; } let map: StringMap = { firstName: "Alice", lastName: "Smith" };
Extending Interfaces
interface Person { name: string; age: number; } interface Employee extends Person { employeeId: number; department: string; } let employee: Employee = { name: "Bob", age: 25, employeeId: 123, department: "Engineering" };
Type Aliases
// Basic type alias type ID = string | number; // Object type type Point = { x: number; y: number; }; // Union types type Status = "success" | "error" | "loading"; // Intersection types type Draggable = { drag: () => void; }; type Resizable = { resize: () => void; }; type UIWidget = Draggable & Resizable;
Interface vs Type
Use interfaces for object shapes and when you need declaration merging. Use type aliases for unions, intersections, primitives, tuples, and advanced type compositions.
Functions
Function Types
// Function declaration function add(a: number, b: number): number { return a + b; } // Arrow function const multiply = (a: number, b: number): number => a * b; // Optional parameters function greet(name: string, greeting?: string): string { return `${greeting ?? "Hello"}, ${name}`; } // Default parameters function log(message: string, level: string = "info"): void { console.log(`[${level}] ${message}`); }
Rest Parameters & Overloads
// Rest parameters function sum(...numbers: number[]): number { return numbers.reduce((a, b) => a + b, 0); } // Function overloads function format(value: string): string; function format(value: number): string; function format(value: string | number): string { return String(value); }
Function Types
// Function type annotation let mathOp: (a: number, b: number) => number; mathOp = (x, y) => x + y; // Callback types function processArray( arr: number[], callback: (item: number) => number ): number[] { return arr.map(callback); } // Type alias for function type Predicate<T> = (value: T) => boolean;
Classes
Basic Class
class Person { // Properties name: string; age: number; private ssn: string; // only accessible in class protected address: string; // accessible in subclasses readonly id: number; // cannot be changed // Constructor constructor(name: string, age: number, id: number) { this.name = name; this.age = age; this.id = id; } // Method greet(): string { return `Hello, I'm ${this.name}`; } // Static method static create(name: string): Person { return new Person(name, 0, 0); } }
Parameter Properties
// Shorthand: declares and assigns in one go class User { constructor( public name: string, private age: number, readonly id: number ) {} getAge(): number { return this.age; } }
Inheritance & Abstract Classes
// Abstract class (cannot be instantiated) abstract class Animal { constructor(public name: string) {} // Abstract method (must be implemented) abstract makeSound(): void; // Concrete method move(): void { console.log(`${this.name} moves`); } } class Dog extends Animal { makeSound(): void { console.log("Woof!"); } } let dog = new Dog("Buddy"); dog.makeSound(); dog.move();
Implementing Interfaces
interface Drawable { draw(): void; } interface Resizable { resize(scale: number): void; } class Rectangle implements Drawable, Resizable { constructor( public width: number, public height: number ) {} draw(): void { console.log("Drawing rectangle"); } resize(scale: number): void { this.width *= scale; this.height *= scale; } }
Generics
Generic Functions
// Basic generic function function identity<T>(value: T): T { return value; } let result = identity<string>("hello"); // explicit let result2 = identity(42); // inferred // Multiple type parameters function pair<K, V>(key: K, value: V): [K, V] { return [key, value]; } let p = pair("age", 30); // [string, number]
Generic Interfaces & Classes
// Generic interface interface Box<T> { value: T; } let stringBox: Box<string> = { value: "hello" }; let numberBox: Box<number> = { value: 42 }; // Generic class class Stack<T> { private items: T[] = []; push(item: T): void { this.items.push(item); } pop(): T | undefined { return this.items.pop(); } } let stack = new Stack<number>(); stack.push(1); stack.push(2);
Generic Constraints
// Constrain to types with length property interface HasLength { length: number; } function logLength<T extends HasLength>(value: T): void { console.log(value.length); } logLength("hello"); // OK: string has length logLength([1, 2, 3]); // OK: array has length // logLength(42); // Error: number doesn't have length // Using keyof function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } let user = { name: "Alice", age: 30 }; let name = getProperty(user, "name"); // OK // let invalid = getProperty(user, "invalid"); // Error
Utility Types
Built-in Utility Types
interface User { id: number; name: string; email: string; age: number; } // Partial<T>: all properties optional type PartialUser = Partial<User>; let updates: PartialUser = { name: "Bob" }; // Required<T>: all properties required type RequiredUser = Required<PartialUser>; // Readonly<T>: all properties readonly type ReadonlyUser = Readonly<User>; let user: ReadonlyUser = { id: 1, name: "Alice", email: "a@b.com", age: 30 }; // user.name = "Bob"; // Error: readonly // Pick<T, K>: select properties type UserPreview = Pick<User, "id" | "name">; // Omit<T, K>: exclude properties type UserWithoutEmail = Omit<User, "email">;
More Utility Types
// Record<K, T>: object with keys K and values T type Roles = Record<"admin" | "user" | "guest", string[]>; let permissions: Roles = { admin: ["read", "write", "delete"], user: ["read", "write"], guest: ["read"] }; // Exclude<T, U>: exclude types from union type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c" // Extract<T, U>: extract types from union type T1 = Extract<"a" | "b" | "c", "a" | "f">; // "a" // NonNullable<T>: exclude null and undefined type T2 = NonNullable<string | null | undefined>; // string // ReturnType<T>: get function return type function getUser() { return { name: "Alice", age: 30 }; } type User2 = ReturnType<typeof getUser>;
Advanced Types
Union & Intersection Types
// Union: value can be one of several types type StringOrNumber = string | number; function format(value: StringOrNumber): string { if (typeof value === "string") { return value.toUpperCase(); } return value.toFixed(2); } // Intersection: combine multiple types type Named = { name: string }; type Aged = { age: number }; type Person = Named & Aged; let person: Person = { name: "Alice", age: 30 };
Type Guards
// typeof guard function print(value: string | number): void { if (typeof value === "string") { console.log(value.toUpperCase()); } else { console.log(value.toFixed(2)); } } // instanceof guard class Dog { bark() { console.log("Woof!"); } } class Cat { meow() { console.log("Meow!"); } } function makeSound(animal: Dog | Cat): void { if (animal instanceof Dog) { animal.bark(); } else { animal.meow(); } } // Custom type guard interface Fish { swim(): void; } interface Bird { fly(): void; } function isFish(animal: Fish | Bird): animal is Fish { return (animal as Fish).swim !== undefined; }
Conditional Types
// T extends U ? X : Y type IsString<T> = T extends string ? "yes" : "no"; type A = IsString<string>; // "yes" type B = IsString<number>; // "no" // Distributive conditional types type ToArray<T> = T extends any ? T[] : never; type StrOrNum = ToArray<string | number>; // string[] | number[]
Mapped Types
// Make all properties optional type MyPartial<T> = { [P in keyof T]?: T[P]; }; // Make all properties readonly type MyReadonly<T> = { readonly [P in keyof T]: T[P]; }; // Map to different type type Stringify<T> = { [P in keyof T]: string; };
Template Literal Types
// String manipulation in types type Greeting = `hello ${"world" | "TypeScript"}`; // "hello world" | "hello TypeScript" // Uppercase/Lowercase utility types type Upper = Uppercase<"hello">; // "HELLO" type Lower = Lowercase<"HELLO">; // "hello" type Cap = Capitalize<"hello">; // "Hello" type Uncap = Uncapitalize<"Hello">; // "hello"
Configuration & Tooling
tsconfig.json
{
"compilerOptions": {
// Target JavaScript version
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
// Module resolution
"moduleResolution": "bundler",
"resolveJsonModule": true,
"esModuleInterop": true,
// Output
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"sourceMap": true,
// Strictness
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noUncheckedIndexedAccess": true,
// Additional checks
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Common CLI Commands
# Install TypeScript npm install -g typescript # Initialize tsconfig.json tsc --init # Compile TypeScript files tsc tsc file.ts tsc --watch # Type checking only (no output) tsc --noEmit # Show version tsc --version
Type Declarations
// .d.ts declaration files // Install types for libraries // npm install --save-dev @types/node // npm install --save-dev @types/react // Declare global variables declare const API_URL: string; // Declare modules without types declare module "*.css" { const content: { [className: string]: string }; export default content; } // Ambient declarations declare namespace MyLib { function greet(name: string): void; }
Enable
strict: true in tsconfig.json for maximum type safety. Start strict from day one for new projects.