Youssef Ameachaq's Blog

Youssef Ameachaq

Typescript notes


What is TypeScript?

TypeScript is JavaScript with added type checking. It allows you to define what kind of data (e.g., strings, numbers, objects) your variables, functions, and other code components can handle. TypeScript code is compiled into regular JavaScript, so it runs anywhere JavaScript does (browsers, Node.js, etc.). The main benefits are:


Key Things You Need to Know

1. Setting Up TypeScript

To use TypeScript, you need:

2. Basic Types

TypeScript lets you define types for variables, parameters, and return values. This ensures your code only works with the expected data.

Example: A user profile function

// JavaScript (no types, error-prone)
function updateUserProfile(userId, name, age) {
  return { userId, name, age };
}
console.log(updateUserProfile("123", "Alice", "30")); // Oops, age is a string, not a number!

// TypeScript (with types, catches errors)
function updateUserProfile(userId: string, name: string, age: number) {
  return { userId, name, age };
}
console.log(updateUserProfile("123", "Alice", 30)); // Works
// console.log(updateUserProfile("123", "Alice", "30")); // Error: Argument of type 'string' is not assignable to parameter of type 'number'

Common Basic Types:

Example: Array of user names

let usernames: string[] = ["Alice", "Bob"];
usernames.push("Charlie");
// usernames.push(123); // Error: Argument of type 'number' is not assignable to parameter of type 'string'

3. Interfaces and Types

Interfaces and type aliases define the shape of objects, making it clear what properties and types are expected.

Example: A shopping cart

// Define an interface for a product
interface Product {
  id: number;
  name: string;
  price: number;
  inStock: boolean;
}

// Use it in a function
function addToCart(product: Product, quantity: number) {
  return {
    product,
    quantity,
    totalPrice: product.price * quantity,
  };
}

const laptop: Product = {
  id: 1,
  name: "Laptop",
  price: 999.99,
  inStock: true,
};

console.log(addToCart(laptop, 2)); // { product: { id: 1, name: "Laptop", ... }, quantity: 2, totalPrice: 1999.98 }
// addToCart({ id: 2, name: "Mouse" }, 1); // Error: Property 'price' is missing

Type vs. Interface:

// Type alias
type UserRole = "admin" | "user" | "guest";

// Interface
interface User {
  id: string;
  role: UserRole;
}

const user: User = { id: "123", role: "admin" };
// const invalidUser: User = { id: "123", role: "manager" }; // Error: "manager" is not assignable to type UserRole

4. Functions and Return Types

You can specify parameter types and return types to ensure functions behave as expected.

Example: Calculate discount

function applyDiscount(price: number, discountPercentage: number): number {
  return price * (1 - discountPercentage / 100);
}

console.log(applyDiscount(100, 20)); // 80
// console.log(applyDiscount("100", 20)); // Error: Argument of type 'string' is not assignable to parameter of type 'number'

Optional Parameters: Use ? for optional parameters.

function greetUser(name: string, greeting?: string): string {
  return `${greeting || "Hello"}, ${name}!`;
}

console.log(greetUser("Alice")); // Hello, Alice!
console.log(greetUser("Bob", "Hi")); // Hi, Bob!

5. Union and Intersection Types

Example: Union for a status

type OrderStatus = "pending" | "shipped" | "delivered";

function updateOrderStatus(orderId: string, status: OrderStatus) {
  console.log(`Order ${orderId} is now ${status}`);
}

updateOrderStatus("123", "shipped"); // Order 123 is now shipped
// updateOrderStatus("123", "cancelled"); // Error: Argument of type '"cancelled"' is not assignable to parameter of type 'OrderStatus'

Example: Intersection for a detailed user

interface BasicUser {
  id: string;
  name: string;
}

interface EmployeeDetails {
  department: string;
  employeeId: number;
}

type Employee = BasicUser & EmployeeDetails;

const employee: Employee = {
  id: "123",
  name: "Alice",
  department: "Engineering",
  employeeId: 456,
};

6. Generics

Generics let you write reusable code that works with any type while keeping type safety.

Example: A reusable list fetcher

function fetchItems<T>(items: T[]): T[] {
  console.log(`Fetched ${items.length} items`);
  return items;
}

const numbers = fetchItems<number>([1, 2, 3]); // Fetched 3 items
const products = fetchItems<Product>([
  { id: 1, name: "Laptop", price: 999.99, inStock: true },
  { id: 2, name: "Mouse", price: 29.99, inStock: true },
]); // Fetched 2 items

Real-world use: Generics are common in libraries like React for components or APIs that handle different data types.

7. Type Assertions

Sometimes you know more about a value’s type than TypeScript does. Use assertions to tell TypeScript what type something is.

Example: Working with DOM elements

const button = document.querySelector("#submit-btn") as HTMLButtonElement;
button.disabled = true; // TypeScript knows this is a button, so `disabled` is valid
// Without `as HTMLButtonElement`, TypeScript only knows it’s an `Element | null`

Note: Use assertions carefully to avoid runtime errors.

8. Modules and TypeScript

TypeScript supports ES Modules and CommonJS. You can import/export types and code.

Example: A user service module

// userService.ts
export interface User {
  id: string;
  name: string;
}

export function getUser(id: string): User {
  return { id, name: "User " + id };
}

// main.ts
import { getUser, User } from "./userService";

const user: User = getUser("123");
console.log(user); // { id: "123", name: "User 123" }

9. Working with JavaScript Libraries

TypeScript works with JavaScript libraries via type definition files (@types). Install them via npm:

npm install @types/node @types/express

Example: Using Express with TypeScript

import express, { Request, Response } from "express";

const app = express();

app.get("/api/users", (req: Request, res: Response) => {
  res.json([{ id: "1", name: "Alice" }]);
});

app.listen(3000, () => console.log("Server running on port 3000"));

If a library lacks types, you can use any or create a basic declaration:

declare module "some-untyped-library";

10. Advanced Features

11. Common Gotchas

12. Real-World Workflow Tips

Example: A Todo App

interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

class TodoApp {
  private todos: Todo[] = [];

  addTodo(text: string): Todo {
    const todo: Todo = { id: this.todos.length + 1, text, completed: false };
    this.todos.push(todo);
    return todo;
  }

  toggleTodo(id: number): Todo | undefined {
    const todo = this.todos.find((t) => t.id === id);
    if (todo) {
      todo.completed = !todo.completed;
    }
    return todo;
  }

  getTodos(): Todo[] {
    return this.todos;
  }
}

const app = new TodoApp();
console.log(app.addTodo("Learn TypeScript")); // { id: 1, text: "Learn TypeScript", completed: false }
console.log(app.toggleTodo(1)); // { id: 1, text: "Learn TypeScript", completed: true }
console.log(app.getTodos()); // [{ id: 1, text: "Learn TypeScript", completed: true }]

14. Debugging and Errors

15. Resources


Why Use TypeScript as a Technical Lead?

Actionable Next Steps

  1. Start Small: Add TypeScript to one module in your project.
  2. Learn Gradually: Focus on basic types, then interfaces, then generics.
  3. Enforce Standards: Set up a tsconfig.json with strict mode and share it with your team.
  4. Integrate Tools: Use TypeScript with your build tools (Webpack, Vite) and CI/CD pipelines.
  5. Train Your Team: Share simple examples like the ones above to get buy-in.