🏠 Home / Hub

🔷 TypeScript Lesson 03 — Functions

← Back to TypeScript Menu  |  🏠 Hub

1. Function Type Annotations

// Parameter types + return type
function add(a: number, b: number): number {
  return a + b;
}

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

// Void — no return value
function log(message: string): void {
  console.log(message);
}

// Never — never returns (throws or infinite loop)
function throwError(msg: string): never {
  throw new Error(msg);
}

// Optional parameters
function greet(name: string, greeting?: string): string {
  return `${greeting ?? "Hello"}, ${name}!`;
}
greet("Ko");           // "Hello, Ko!"
greet("Ko", "Hi");     // "Hi, Ko!"

// Default parameters
function createUser(name: string, role: string = "user", active: boolean = true) {
  return { name, role, active };
}

// Rest parameters
function sum(...numbers: number[]): number {
  return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4, 5);   // 15

2. Function Types as Values

// Function type annotation
type Transformer = (input: string) => string;
type Calculator  = (a: number, b: number) => number;
type Callback    = (err: Error | null, data: string) => void;

// Higher-order functions
function applyTransform(text: string, fn: Transformer): string {
  return fn(text);
}

const upper: Transformer = (s) => s.toUpperCase();
const trim:  Transformer = (s) => s.trim();

applyTransform("  hello  ", trim);   // "hello"
applyTransform("hello", upper);      // "HELLO"

// Array higher-order with types
function filterUsers<T extends { active: boolean }>(items: T[], active: boolean): T[] {
  return items.filter(item => item.active === active);
}

// Event handler types
type EventHandler<T = Event> = (event: T) => void;
const handleClick: EventHandler<MouseEvent> = (e) => {
  console.log(e.clientX, e.clientY);
};

3. Overloads

// Function overloads — same function, different signatures
function format(value: string): string;
function format(value: number): string;
function format(value: Date): string;
// Implementation (must handle all cases)
function format(value: string | number | Date): string {
  if (typeof value === "string") return value.trim();
  if (typeof value === "number") return value.toFixed(2);
  return value.toISOString().split("T")[0];
}

format("  hello  ");   // "hello"
format(3.14159);       // "3.14"
format(new Date());    // "2024-01-15"

// API request with overloads
interface User { id: number; name: string; }
interface Post { id: number; title: string; }

function fetchData(endpoint: "/users"): Promise<User[]>;
function fetchData(endpoint: "/posts"): Promise<Post[]>;
function fetchData(endpoint: string): Promise<unknown> {
  return fetch(endpoint).then(r => r.json());
}

const users = await fetchData("/users");  // type: User[]
const posts = await fetchData("/posts");  // type: Post[]

4. Async Functions

// async function always returns Promise<T>
async function getUser(id: number): Promise<User | null> {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) return null;
  return res.json() as Promise<User>;
}

// Error-safe fetch wrapper
async function safeFetch<T>(url: string): Promise<{ data: T | null; error: string | null }> {
  try {
    const res = await fetch(url);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const data: T = await res.json();
    return { data, error: null };
  } catch (err) {
    const msg = err instanceof Error ? err.message : "Unknown error";
    return { data: null, error: msg };
  }
}

// Usage
const { data: users, error } = await safeFetch<User[]>("/api/users");

// Typed API service
interface ApiResponse<T> {
  data: T;
  meta: { total: number; page: number };
}

async function getUsers(page = 1): Promise<ApiResponse<User[]>> {
  const res = await fetch(`/api/users?page=${page}`);
  return res.json();
}
💡 async function return type = Promise<T> → IDE auto-complete ကောင်းဖို့ explicit ထည့်ပါ

← TS 02  |  Next: TS 04 → Classes →

📌 Study Checklist