🔷

A language tour

The Safety of TypeScript

JavaScript grew up across thirty years of accumulation. TypeScript is what it learned.

scroll

01 — Type Safety

Catch errors at compile time

TypeScript adds static typing to JavaScript. It catches type errors before your code runs, making large applications more reliable.

types.ts
// Variables have types
let name: string = "Alice";
let age: number = 30;
let isActive: boolean = true;

// Functions specify parameter and return types
function greet(person: string): string {
  return `Hello, ${person}!`;
}

// TypeScript catches errors
greet(123); // Error: Argument of type 'number' is not assignable to parameter of type 'string'

Types document your intent and prevent runtime errors — the compiler becomes your first line of defense.


02 — Interfaces

Shape your data structures

Interfaces define the shape of objects. They create contracts that your code must follow, making APIs self-documenting.

"A type annotation is the most efficient form of documentation — it can never drift from the code it describes."

— The TypeScript design philosophy
interfaces.ts
interface User {
  id: number;
  name: string;
  email: string;
  isActive?: boolean; // Optional property
}

function createUser(userData: User): User {
  return {
    id: userData.id,
    name: userData.name,
    email: userData.email,
    isActive: userData.isActive ?? true
  };
}

const user = createUser({
  id: 1,
  name: "Alice",
  email: "[email protected]"
});

Interfaces define contracts — the compiler ensures your data matches the expected shape.


03 — Generics

Type-safe abstractions

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

generics.ts
// One wrapper type for every API response
interface ApiResponse<T> {
  data: T;
  status: number;
  error: string | null;
}

// One function handles every endpoint
async function fetchJson<T>(url: string): Promise<ApiResponse<T>> {
  const res = await fetch(url);
  const data: T = await res.json();
  return { data, status: res.status, error: null };
}

// TypeScript infers the full type from usage
const result = await fetchJson<User[]>('/api/users');
result.data.forEach(u => console.log(u.name)); // u.name: string ✓

The compiler infers T as User[] at the call site — one function, every endpoint, full type safety throughout.


04 — Union Types

Multiple possibilities, one type

Union types let a value be one of several types. They model real-world data that can take different forms.

unions.ts
// Union type
type StringOrNumber = string | number;

function printId(id: StringOrNumber) {
  if (typeof id === "string") {
    console.log(`String ID: ${id.toUpperCase()}`);
  } else {
    console.log(`Number ID: ${id}`);
  }
}

// Discriminated unions
type Success = { type: "success"; data: string };
type Error = { type: "error"; message: string };
type Result = Success | Error;

function handleResult(result: Result) {
  if (result.type === "success") {
    console.log(result.data);
  } else {
    console.error(result.message);
  }
}

Unions model choice — a value can be this OR that, with type-safe handling of each case.


05 — Gradual Adoption

Types when you need them

TypeScript is a superset of JavaScript. You can add types gradually — start with any .js file and rename it to .ts.

gradual.ts
// Plain JavaScript is valid TypeScript — rename .js to .ts
function add(a, b) {
  return a + b;
}

// Add types incrementally as you understand each function
function multiply(a: number, b: number): number {
  return a * b;
}

// 'unknown' for values you can't predict — safer than 'any'
let incoming: unknown = parseFromLegacyApi();
if (typeof incoming === "string") {
  console.log(incoming.toUpperCase()); // narrowed: TypeScript knows it's a string
}

// Type assertion for DOM elements you know the shape of
const input = document.getElementById("email") as HTMLInputElement;

unknown is the honest alternative to any — it forces you to narrow the type before using it, rather than silently bypassing the type system.


06 — The Whole Picture

TypeScript's philosophy

TypeScript brings honesty to JavaScript. The types describe what's actually true about your data — not what you hoped was true at 2am before a release.

🛡️

Type Safety

Catches errors at compile time, prevents runtime bugs, and serves as living documentation.

📈

Scalable

Makes large codebases manageable with interfaces, generics, and structural typing.

🔄

Gradual

Add types incrementally — works with existing JavaScript code and teams.

🎯

Tooling

Excellent IDE support with autocomplete, refactoring, and instant error feedback.

🌐

Ecosystem

Compiles to JavaScript — runs everywhere JS does, with full interop.

📚

Standards

Based on ECMAScript standards, includes future JS features as proposals stabilize.