TypeScript logoTypeScriptv7INTERMEDIATE

TypeScript

TypeScript cheat sheet covering types, interfaces, generics, utility types, type guards, and advanced type system features with examples.

12 min read
typescripttypesinterfacesgenericsjavascript

Sign in to mark items as known and track your progress.

Sign in

Basic Types

Primitive Types

TypeScript basic primitive types and type annotations

typescript
// Basic types
let name: string = "John"
let age: number = 30
let isActive: boolean = true
let value: any = "anything"
let id: symbol = Symbol("id")
let big: bigint = 100n

// Arrays
let numbers: number[] = [1, 2, 3]
let names: Array<string> = ["Alice", "Bob"]

// Tuple
let tuple: [string, number] = ["hello", 10]

// Enum
enum Color { Red, Green, Blue }
let color: Color = Color.Green
💡 Use unknown instead of any when possible
📌 const assertions create readonly literal types
✅ Enable strictNullChecks for better null safety

Type Aliases, Unions & Intersections

Create custom types with aliases, combine with unions and intersections

typescript
// Type alias
type ID = string | number;

// Union (one of)
type Status = "active" | "inactive" | "pending";

// Intersection (combine all)
type Employee = Person & { company: string };
💡 Union (|) means "one of these" — intersection (&) means "all of these combined"
⚡ Literal types restrict values to exact strings, numbers, or booleans
📌 Intersections merge all properties — conflicting properties become never
🟢 Use type aliases for unions/intersections; use interfaces for object shapes you might extend

Enums

Named constants with numeric or string values

typescript
enum Direction {
  Up,       // 0
  Down,     // 1
  Left,     // 2
  Right,    // 3
}

enum Status {
  Active = "ACTIVE",
  Inactive = "INACTIVE",
}

const dir: Direction = Direction.Up;
💡 String enums are preferred — they are readable in logs and don't have reverse mapping overhead
⚡ Use const enum to inline values at compile time — zero runtime cost
📌 Many teams prefer "as const" objects over enums — they are simpler and tree-shakable
🟢 keyof typeof MyEnum gives you a union of the enum key names as strings
enumconst-enum

Tuples & Readonly

Fixed-length typed arrays and immutable modifiers

typescript
// Tuple — fixed length, typed positions
const coord: [number, number] = [10, 20];
const entry: [string, number] = ["age", 30];

// Readonly — prevents mutation
const point: readonly [number, number] = [10, 20];
const names: readonly string[] = ["Alice", "Bob"];
💡 Tuples are arrays with fixed length and typed positions — great for return values
⚡ as const makes everything deeply readonly AND narrows to literal types
📌 readonly on arrays prevents push/pop/splice — the reference can still be reassigned
🟢 Named tuples (labels) improve readability but have no runtime effect
tuplereadonlyas-const

Functions

Function Types

Type annotations for functions and their parameters

typescript
// Function declaration
function add(a: number, b: number): number {
  return a + b
}

// Arrow function
const multiply = (a: number, b: number): number => a * b

// Function type
type MathFn = (a: number, b: number) => number
const subtract: MathFn = (a, b) => a - b

// Optional parameters
function greet(name: string, title?: string): string {
  return title ? `${title} ${name}` : `Hello ${name}`
}

// Default parameters
function log(message: string, level: string = "info"): void {
  console.log(`[${level}] ${message}`)
}
💡 Use optional parameters instead of overloads when possible
📌 Arrow functions preserve lexical this
✅ Always type function parameters

Function Overloading

Define multiple function signatures for different parameter types

typescript
// Function overloading
function create(name: string): string
function create(age: number): number
function create(value: string | number): string | number {
  if (typeof value === "string") {
    return `Name: ${value}`
  }
  return value * 2
}

// Method overloading in class
class Calculator {
  add(a: number, b: number): number
  add(a: string, b: string): string
  add(a: any, b: any): any {
    return a + b
  }
}
⚠️ Overload signatures must be compatible with implementation
💡 Order overloads from most specific to least specific
📌 Consider union types instead of overloads

Interfaces & Classes

Interfaces

Define object shapes and contracts for type checking

typescript
// Basic interface
interface User {
  name: string
  age: number
  email?: string  // Optional
  readonly id: number  // Readonly
}

// Extending interfaces
interface Admin extends User {
  role: string
  permissions: string[]
}

// Function in interface
interface Greetable {
  name: string
  greet(): void
}

// Index signatures
interface StringDictionary {
  [key: string]: string
}
💡 Interfaces can be extended and merged
📌 Use interfaces for object shapes
✅ Prefer interfaces over type aliases for objects

Classes

Object-oriented programming with TypeScript classes

typescript
// Basic class
class Person {
  name: string
  age: number
  
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  
  greet(): string {
    return `Hello, I'm ${this.name}`
  }
}

// Access modifiers
class Employee {
  public name: string
  private salary: number
  protected department: string
  readonly id: number
  
  constructor(name: string, salary: number) {
    this.name = name
    this.salary = salary
    this.id = Math.random()
  }
}
💡 Use parameter properties to reduce boilerplate
🔒 Private fields start with # in modern TS
📌 Abstract classes cannot be instantiated

Inheritance

Class inheritance and method overriding in TypeScript

typescript
// Basic inheritance
class Animal {
  name: string
  
  constructor(name: string) {
    this.name = name
  }
  
  move(distance: number = 0): void {
    console.log(`${this.name} moved ${distance}m`)
  }
}

class Dog extends Animal {
  bark(): void {
    console.log("Woof! Woof!")
  }
}

// Method overriding
class Cat extends Animal {
  move(distance: number = 5): void {
    console.log("Cat prowling...")
    super.move(distance)
  }
}
💡 Use super() to call parent constructor
📌 Protected members accessible in derived classes
✅ Mixins provide multiple inheritance pattern

Generics

Generic Functions

Create reusable functions that work with multiple types

typescript
// Generic function
function identity<T>(value: T): T {
  return value
}

// Using generic function
const num = identity<number>(42)
const str = identity<string>("hello")
const auto = identity(true)  // Type inference

// Generic with arrays
function first<T>(array: T[]): T | undefined {
  return array[0]
}

// Multiple type parameters
function pair<T, U>(first: T, second: U): [T, U] {
  return [first, second]
}
💡 TypeScript often infers generic types automatically
📌 Use constraints to limit generic types
✅ Generics make code reusable and type-safe

Generic Classes & Interfaces

Build flexible classes and interfaces with generic types

typescript
// Generic class
class Box<T> {
  private value: T
  
  constructor(value: T) {
    this.value = value
  }
  
  getValue(): T {
    return this.value
  }
  
  setValue(value: T): void {
    this.value = value
  }
}

const numberBox = new Box<number>(42)
const stringBox = new Box<string>("hello")

// Generic interface
interface Container<T> {
  value: T
  add(item: T): void
  remove(): T | undefined
}
💡 Generic classes create type-safe data structures
📌 Static methods can have their own generic parameters
✅ Use generic constraints for type safety

Type Operations

Operators and assertions for querying and transforming types

Type Assertions (as, satisfies, as const)

Tell the compiler about types it cannot infer automatically

typescript
// as — assert a type
const input = document.getElementById("name") as HTMLInputElement;

// satisfies — validate without widening
const palette = {
  red: [255, 0, 0],
  green: "#00ff00",
} satisfies Record<string, string | number[]>;

// as const — narrow to literal types
const routes = ["home", "about", "contact"] as const;
💡 satisfies validates WITHOUT widening — you keep literal types and autocomplete
⚡ as const is perfect for config objects, routes, and enum-like arrays
📌 Avoid "as" when possible — it overrides the compiler and hides real errors
🟢 typeof ARRAY[number] extracts a union of all values from an as const array
assatisfiesas-constassertion

keyof, typeof & Indexed Access

Query types from existing values and access type properties by key

typescript
// keyof — union of all keys
type User = { name: string; age: number };
type UserKey = keyof User; // "name" | "age"

// typeof — get type from a value
const config = { port: 3000, host: "localhost" };
type Config = typeof config; // { port: number; host: string }

// Indexed access — look up a type by key
type Age = User["age"]; // number
💡 keyof + generics is the foundation for type-safe property access functions
⚡ typeof gets a type from a VALUE — essential for config objects and function return types
📌 T[K] indexed access works on nested types too: User["address"]["city"]
🟢 Array[number] extracts the element type from an array — combine with as const for unions
keyoftypeofindexed-access

Advanced Types

Utility Types

Built-in generic types for common type transformations

typescript
Partial<User>         // all props optional
Required<User>        // all props required
Pick<User, "name" | "email">  // select props
Omit<User, "password">        // exclude props
Record<string, number>        // key-value object
Readonly<User>                // all props readonly
💡 Pick and Omit are your go-to for creating API response types from full models
⚡ Record<K, V> is cleaner than { [key: string]: V } for objects with known key types
📌 Exclude/Extract work on union types — Omit/Pick work on object types
🟢 ReturnType<typeof fn> extracts a function return type without writing it manually

Type Guards & Narrowing

All the ways to narrow types in conditional blocks

typescript
// typeof
if (typeof x === "string") { x.toUpperCase(); }

// instanceof
if (err instanceof Error) { err.message; }

// in operator
if ("email" in user) { user.email; }

// Custom type predicate
function isString(x: unknown): x is string {
  return typeof x === "string";
}
💡 Discriminated unions with a "kind" field + switch is the most type-safe branching pattern
⚡ Custom type predicates (is keyword) let you create reusable narrowing functions
📌 The assertNever pattern catches missing switch cases at compile time — essential for unions
🟢 TypeScript narrows automatically with typeof, instanceof, in, truthiness, and equality checks

Mapped, Conditional & Template Literal Types

Transform and construct types programmatically

typescript
// Mapped type
type Optional<T> = { [K in keyof T]?: T[K] };

// Conditional type
type IsString<T> = T extends string ? true : false;

// Template literal type
type EventName = `on${Capitalize<"click" | "focus">}`;
// "onClick" | "onFocus"
💡 Mapped types are how Partial, Required, Readonly, and Record are built internally
⚡ Template literal types generate union combinations — perfect for CSS class builders
📌 infer extracts a type variable inside conditional types — powers ReturnType, Awaited, etc.
🟢 Key remapping with "as" + Capitalize builds getters, setters, and event handlers from shapes

Decorators

Stage 3 decorators for classes, methods, and properties (TypeScript 5+)

Decorators (TypeScript 5+)

Annotate and modify classes and their members with decorator functions

typescript
function log(target: any, context: ClassMethodDecoratorContext) {
  return function (...args: any[]) {
    console.log(`Calling ${String(context.name)}`);
    return target.apply(this, args);
  };
}

class Api {
  @log
  getUsers() { return []; }
}
💡 TypeScript 5+ uses Stage 3 decorators — different API from the old experimentalDecorators
⚡ Decorator factories (functions returning decorators) let you pass config parameters
📌 Common in NestJS, Angular, and TypeORM — less common in React/frontend code
🟢 The context parameter tells you what is being decorated (method, field, class, accessor)
decoratorsclasstypescript-5

Modules & Namespaces

Imports & Exports

ES6 module syntax for importing and exporting code

typescript
// Named exports
export const API_URL = "https://api.example.com"
export function fetchData() { }
export class User { }
export type UserType = { name: string }
export interface UserInterface { }

// Default export
export default class App { }

// Named imports
import { API_URL, fetchData } from "./api"
import type { UserType } from "./types"

// Default import
import App from "./App"

// Namespace import
import * as Utils from "./utils"

// Combined import
import React, { useState, useEffect } from "react"
💡 Use type-only imports for better tree-shaking
📌 Dynamic imports for code splitting
✅ Re-export to create public API

Declaration Files

Type declarations for JavaScript libraries and modules

typescript
// Ambient declarations (*.d.ts)
declare module "untyped-module" {
  export function doSomething(): void
  export const value: string
}

// Global declarations
declare const VERSION: string
declare function analyticsTrack(event: string): void

// Module declarations
declare module "*.css" {
  const content: { [className: string]: string }
  export default content
}

declare module "*.svg" {
  const content: React.FC<React.SVGProps<SVGSVGElement>>
  export default content
}
💡 Use @types packages for library types
📌 .d.ts files contain only type declarations
✅ Declare modules for assets and untyped packages

TSConfig Reference

Compiler Options Reference

Complete reference of TypeScript compiler options with descriptions and values

typescript
// tsconfig.json
{
  "compilerOptions": {
    // Target & Module
    "target": "ES2020",              // ES5, ES2020, ES2022, ESNext
    "module": "commonjs",            // commonjs, ESNext, node16
    "lib": ["ES2020", "DOM"],        // Standard library types
    
    // Type Checking
    "strict": true,                  // Enable all strict checks
    "noImplicitAny": true,          // Error on 'any' type
    "strictNullChecks": true,       // Strict null/undefined checks
    
    // Module Resolution
    "moduleResolution": "bundler",  // bundler, node16, nodenext
    "esModuleInterop": true,        // CommonJS interop
    "resolveJsonModule": true,      // Import JSON files
    
    // Emit
    "outDir": "./dist",             // Output directory
    "rootDir": "./src",             // Source directory
    "sourceMap": true,              // Generate sourcemaps
    "declaration": true,            // Generate .d.ts files
    
    // JavaScript
    "allowJs": true,                // Allow .js files
    "checkJs": false,               // Type check .js files
    
    // Skip Checks
    "skipLibCheck": true,           // Skip .d.ts checking
    "forceConsistentCasingInFileNames": true
  }
}
💡 Start with strict: true and adjust as needed
📌 Use paths for clean import aliases
⚡ skipLibCheck speeds up compilation significantly
✅ Different project types need different configs