Skip to main content
This reference covers all TypeScript types, interfaces, enums, and patterns used in the ML Store project.

Basic Types

TypeDescriptionExample
stringText valuesconst name: string = "John"
numberNumeric values (int & float)const age: number = 25
booleantrue/false valuesconst isActive: boolean = true
nullIntentional absenceconst value: null = null
undefinedUninitialized valuelet value: undefined
anyAny type (avoid)const data: any = {...}
voidNo return valuefunction log(): void { }
neverNever returnsfunction error(): never { throw new Error() }

Array Types

// Array notation
const numbers: number[] = [1, 2, 3];
const names: string[] = ["Alice", "Bob"];

// Generic notation
const items: Array<string> = ["item1", "item2"];

// Mixed array (tuple)
const tuple: [string, number] = ["age", 25];

Project Interfaces

Category Interface

interface Category {
  id: number;
  name: string;
  image: string;
  slug: string;
}
PropertyTypeDescription
idnumberUnique category identifier
namestringCategory name (e.g., “Electronics”)
imagestringURL to category image
slugstringURL-friendly name

Product Interface

interface Product {
  id: number;
  title: string;
  slug: string;
  price: number;
  description: string;
  category: Category;
  images: string[];
}
PropertyTypeDescriptionExample
idnumberUnique product ID101
titlestringProduct name"Laptop HP 15"
slugstringURL slug"laptop-hp-15"
pricenumberPrice in currency799.99
descriptionstringProduct description"Powerful laptop..."
categoryCategoryNested category object{ id: 1, name: "Electronics", ... }
imagesstring[]Array of image URLs["url1.jpg", "url2.jpg"]

AppState Interface

interface AppState {
  status: LoadingState;
  products: Product[];
  error: string | null;
}
PropertyTypeDescription
statusLoadingStateCurrent loading state (enum)
productsProduct[]Array of products
errorstring | nullError message or null
string | null is a union type - the value can be either a string OR null.

Enums

LoadingState Enum

enum LoadingState {
  Idle = "IDLE",
  Loading = "LOADING",
  Success = "SUCCESS",
  Error = "ERROR"
}
Usage:
let appState: AppState = {
  status: LoadingState.Idle,  // ✓ Type-safe
  products: [],
  error: null
};

// Instead of error-prone strings:
// status: "IDLE"  // ✗ Typos not caught

Union Types

Union types allow a value to be one of several types:
// Simple union
let value: string | number;
value = "hello";  // ✓
value = 42;       // ✓

// Union with null (nullable)
let error: string | null = null;
error = "Something went wrong";  // ✓

// Multiple unions
type Status = "pending" | "approved" | "rejected";
let status: Status = "pending";

Generics

Generic Function

function getElement<T extends HTMLElement>(selector: string): T {
  const element = document.querySelector<T>(selector);
  if (!element) {
    throw new Error(`Element not found: ${selector}`);
  }
  return element;
}
Syntax: <T extends HTMLElement>
  • T is a type parameter (placeholder for any type)
  • extends HTMLElement means T must be HTMLElement or a subtype
  • When you call the function, you specify what T is
Usage:
// T becomes HTMLButtonElement
const btn = getElement<HTMLButtonElement>("#my-btn");
btn.disabled = true;  // ✓ TypeScript knows it's a button

// T becomes HTMLInputElement
const input = getElement<HTMLInputElement>("#search");
input.value = "text";  // ✓ TypeScript knows it has .value

Generic Types

// Generic array
const items: Array<Product> = [];

// Generic Map
const cart: Map<number, number> = new Map();
//             ↑       ↑
//           key type  value type

// Generic Promise
async function fetchData(): Promise<Product[]> {
  // Returns a promise that resolves to Product[]
}

Type Aliases

// Simple alias
type ID = number;
type Username = string;

// Object type
type Point = {
  x: number;
  y: number;
};

// Union type alias
type Status = "idle" | "loading" | "success" | "error";

Function Types

Function Declarations

// Named function
function add(a: number, b: number): number {
  return a + b;
}

// Arrow function
const multiply = (a: number, b: number): number => {
  return a * b;
};

// Implicit return
const subtract = (a: number, b: number): number => a - b;

Function Type Signatures

// Variable with function type
let calculate: (x: number, y: number) => number;

calculate = (a, b) => a + b;  // ✓
calculate = (a, b) => `${a}`;  // ✗ Returns string, not number

Async Functions

async function fetchProducts(limit: number = 20): Promise<Product[]> {
  const response = await fetch(`${API_URL}?limit=${limit}`);
  const data = await response.json() as Product[];
  return data;
}
Async functions always return a Promise. Even if you return Product[], the actual return type is Promise<Product[]>.

Optional and Default Parameters

// Optional parameter (?)
function greet(name?: string): string {
  return name ? `Hello, ${name}` : "Hello";
}

// Default parameter (=)
function fetchProducts(limit: number = 20): Promise<Product[]> {
  // limit defaults to 20 if not provided
}

// Optional properties in interfaces
interface User {
  name: string;
  age?: number;  // Optional
}

Type Assertions

// Using 'as' keyword
const data = await response.json() as Product[];

// Angle bracket syntax (not in JSX)
const data = <Product[]>await response.json();

// DOM element assertion
const input = document.getElementById("search") as HTMLInputElement;
Type assertions tell TypeScript “trust me, I know this type” but don’t actually change the runtime value. Use carefully!

Utility Types

Built-in Utility Types

// Partial - makes all properties optional
interface Product {
  id: number;
  title: string;
  price: number;
}

type PartialProduct = Partial<Product>;
// { id?: number; title?: string; price?: number; }

// Required - makes all properties required
type RequiredProduct = Required<PartialProduct>;

// Pick - select specific properties
type ProductPreview = Pick<Product, "id" | "title">;
// { id: number; title: string; }

// Omit - exclude specific properties
type ProductWithoutId = Omit<Product, "id">;
// { title: string; price: number; }

// Readonly - makes properties read-only
type ReadonlyProduct = Readonly<Product>;

Type Guards

// typeof guard
function process(value: string | number) {
  if (typeof value === "string") {
    // TypeScript knows value is string here
    return value.toUpperCase();
  } else {
    // TypeScript knows value is number here
    return value.toFixed(2);
  }
}

// instanceof guard
if (element instanceof HTMLInputElement) {
  console.log(element.value);
}

// Truthiness guard
if (error) {
  // error is truthy (not null or undefined)
  console.error(error);
}

Common Patterns from Project

1. State Management Type

interface AppState {
  status: LoadingState;
  products: Product[];
  error: string | null;
}

let appState: AppState = {
  status: LoadingState.Idle,
  products: [],
  error: null
};

2. API Response Typing

async function fetchProducts(limit: number = 20): Promise<Product[]> {
  const response = await fetch(`${API_URL}?limit=${limit}`);
  
  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
  }
  
  const data = await response.json() as Product[];
  return data;
}

3. Generic Helper Function

function getElement<T extends HTMLElement>(selector: string): T {
  const element = document.querySelector<T>(selector);
  if (!element) {
    throw new Error(`Element not found: ${selector}`);
  }
  return element;
}

// Usage
const button = getElement<HTMLButtonElement>("#load-btn");
const input = getElement<HTMLInputElement>("#search-input");

4. Map Data Structure

const cart: Map<number, number> = new Map();

// Add to cart
cart.set(productId, quantity);

// Get quantity
const qty = cart.get(productId);  // number | undefined

// Check if exists
if (cart.has(productId)) {
  // ...
}

// Remove item
cart.delete(productId);

5. Event Handler Typing

function handleClick(event: MouseEvent): void {
  const target = event.target as HTMLElement;
  const button = target.closest("button");
  // ...
}

element.addEventListener("click", handleClick);

Type Inference

TypeScript can often infer types automatically:
// Type inferred as string
const name = "Alice";

// Type inferred as number
const age = 25;

// Type inferred as number[]
const numbers = [1, 2, 3];

// Type inferred as Promise<Response>
const response = fetch("/api/data");

// Return type inferred as number
function add(a: number, b: number) {
  return a + b;  // Returns number
}
Let TypeScript infer types when they’re obvious. Only add explicit types when needed for clarity or to catch errors.

Best Practices

Use interfaces for object shapes
Use enums for fixed sets of values
Use union types for values that can be multiple types
Avoid any - use unknown if you must
Use generics for reusable, type-safe functions
Let TypeScript infer types when obvious
Don’t abuse type assertions (as). If you find yourself using them frequently, your types might be wrong.

Quick Reference Card

PatternSyntaxUse Case
Interfaceinterface Name { }Object shapes
Type Aliastype Name = ...Unions, primitives
Enumenum Name { }Fixed constants
Unionstring | numberMultiple types
Optionalproperty?: typeOptional fields
Generics<T extends Base>Reusable types
ArrayType[] or Array<Type>Lists
PromisePromise<Type>Async results
Function(param: Type) => ReturnTypeFunction signatures
Assertionvalue as TypeOverride type

Next Steps

TypeScript Basics

Learn TypeScript fundamentals

Common Patterns

Code patterns and examples

HTML Tags

HTML reference guide

Build docs developers (and LLMs) love