👑 Premium Sign in Sign up

Language lab · Intermediate

🔷 TypeScript

Concept → trace → write code → run tests → explain why → improve → mini-project. Start in the browser if you like; set up your own computer when you are ready.

💻 Runs on your computerOfficial download & docs ↗

📖 Topics with real code (12)

Every verified output below was produced by running the code with Version 5.6.3 on 5 Nov 2026. Open a topic to edit the code and run it right here in your browser.

🌱 Beginner (4)

Types and type inference

TypeScript adds types to JavaScript and checks them before the code runs. Annotate with : type, or let the compiler infer. Union types allow one of several types.

let age: number = 15;
const studentName: string = "Asha";
const isStudent: boolean = true;
let id: string | number = 42;      // union
id = "S-42";
const marks = [88, 95];            // inferred number[]
console.log(studentName, age, isStudent, id, marks, typeof id);
const tuple: [string, number] = ["Ravi", 95];
console.log(tuple[0].toUpperCase(), tuple[1].toFixed(1));

✅ Verified output

Asha 15 true S-42 [ 88, 95 ] string
RAVI 95.0
Functions with typed parameters

Parameters and return values carry types. Optional parameters use ?, defaults use =. The compiler refuses a call with the wrong types.

function area(length: number, width: number = 1): number {
  return length * width;
}
function greet(name: string, title?: string): string {
  return title ? `Namaste, ${title} ${name}!` : `Namaste, ${name}!`;
}
const average = (...nums: number[]): number => nums.reduce((s, x) => s + x, 0) / nums.length;
console.log(area(5, 3), area(7), greet("Ravi"), greet("Meena", "Dr."), average(4, 9, 2, 7));

✅ Verified output

15 7 Namaste, Ravi! Namaste, Dr. Meena! 5.5
Conditionals and narrowing

Inside an if that checks typeof or a property, TypeScript narrows the type, so only safe operations are allowed in each branch.

function describe(value: string | number | boolean): string {
  if (typeof value === "string") return `text of length ${value.length}`;
  if (typeof value === "number") return value >= 35 ? "pass mark" : "fail mark";
  return value ? "yes" : "no";
}
for (const v of ["hello", 78, 20, false]) console.log(v, "->", describe(v));

✅ Verified output

hello -> text of length 5
78 -> pass mark
20 -> fail mark
false -> no
Loops over typed arrays

for...of, forEach and classic for loops work as in JavaScript, but the element type is known, so typos are caught.

const subjects: string[] = ["maths", "science", "telugu"];
for (const s of subjects) console.log(s.toUpperCase());
subjects.forEach((s, i) => console.log(i, s.length));
let total = 0;
for (let i = 1; i <= 10; i++) {
  if (i % 2) continue;
  total += i;
}
console.log("sum of evens", total);

✅ Verified output

MATHS
SCIENCE
TELUGU
0 5
1 7
2 6
sum of evens 30

🌿 Intermediate (4)

Interfaces and type aliases

An interface describes the shape of an object; readonly fields cannot change; optional fields use ?.

interface Student {
  readonly roll: string;
  name: string;
  marks: number;
  email?: string;
}
type Grade = "A+" | "A" | "Pass" | "Fail";
function grade(s: Student): Grade {
  return s.marks >= 90 ? "A+" : s.marks >= 75 ? "A" : s.marks >= 35 ? "Pass" : "Fail";
}
const list: Student[] = [{ roll: "R1", name: "Asha", marks: 88 }, { roll: "R2", name: "Ravi", marks: 95, email: "r@example.edu" }];
for (const s of list) console.log(s.name, grade(s), s.email ?? "no email");

✅ Verified output

Asha A no email
Ravi A+ r@example.edu
Classes with access modifiers

private, protected and public control access at compile time; parameter properties declare and assign fields in one line.

class BankAccount {
  constructor(public readonly owner: string, private balance: number = 0) {}
  deposit(amount: number): void {
    if (amount <= 0) throw new RangeError("amount must be positive");
    this.balance += amount;
  }
  get current(): number {
    return this.balance;
  }
}
const acc = new BankAccount("Asha", 500);
acc.deposit(250);
console.log(acc.owner, acc.current);

✅ Verified output

Asha 750
Inheritance, abstract classes and interfaces

An abstract class cannot be created directly; subclasses must implement its abstract members. A class can implement several interfaces.

interface Named { name(): string; }
abstract class Shape implements Named {
  abstract area(): number;
  name(): string { return this.constructor.name; }
  describe(): string { return `${this.name()} ${this.area().toFixed(2)}`; }
}
class Circle extends Shape { constructor(private r: number) { super(); } area() { return Math.PI * this.r ** 2; } }
class Rect extends Shape { constructor(private w: number, private h: number) { super(); } area() { return this.w * this.h; } }
const shapes: Shape[] = [new Circle(1), new Rect(3, 4)];
shapes.forEach((s) => console.log(s.describe()));

✅ Verified output

Circle 3.14
Rect 12.00
Errors and the unknown type

catch gives unknown: check it with instanceof before use. Custom error classes carry extra data.

class ValidationError extends Error {
  constructor(public field: string, message: string) {
    super(message);
    this.name = "ValidationError";
  }
}
function parseAge(text: string): number {
  const n = Number(text);
  if (!Number.isInteger(n) || n < 0 || n > 120) throw new ValidationError("age", `bad age: ${text}`);
  return n;
}
for (const input of ["15", "abc", "200"]) {
  try {
    console.log("age", parseAge(input));
  } catch (e: unknown) {
    if (e instanceof ValidationError) console.log(e.name, e.field, e.message);
  }
}

✅ Verified output

age 15
ValidationError age bad age: abc
ValidationError age bad age: 200

🌳 Advanced (4)

Generics

A generic function or class keeps the exact type of its input. Constraints (extends) limit which types are allowed.

function first<T>(items: T[]): T | undefined {
  return items[0];
}
function maxBy<T>(items: T[], key: (t: T) => number): T {
  return items.reduce((best, x) => (key(x) > key(best) ? x : best));
}
class Stack<T> {
  private items: T[] = [];
  push(x: T) { this.items.push(x); return this; }
  pop(): T | undefined { return this.items.pop(); }
  get size() { return this.items.length; }
}
console.log(first([3, 1]), first(["a", "b"]), maxBy([{ n: "Asha", m: 88 }, { n: "Ravi", m: 95 }], (s) => s.m).n);
const st = new Stack<string>().push("a").push("b");
console.log(st.pop(), st.size);

✅ Verified output

3 a Ravi
b 1
Utility and mapped types

Built-in utility types (Partial, Pick, Record, Readonly) build new types from old ones. keyof gives the property names.

interface Course { code: string; title: string; credits: number; }
type CourseUpdate = Partial<Course>;
type CourseCard = Pick<Course, "code" | "title">;
const catalog: Record<string, Course> = { CS101: { code: "CS101", title: "Python", credits: 4 } };
function update(c: Course, patch: CourseUpdate): Course {
  return { ...c, ...patch };
}
function getField<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
const updated = update(catalog.CS101, { credits: 5 });
const card: CourseCard = { code: updated.code, title: updated.title };
console.log(updated, card, getField(updated, "credits"));

✅ Verified output

{ code: 'CS101', title: 'Python', credits: 5 } { code: 'CS101', title: 'Python' } 5
Discriminated unions

A shared literal field (kind) lets TypeScript know exactly which variant you have in each switch branch; the never check makes the switch exhaustive.

type Shape =
  | { kind: "circle"; r: number }
  | { kind: "rect"; w: number; h: number }
  | { kind: "triangle"; b: number; h: number };
function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.r ** 2;
    case "rect": return s.w * s.h;
    case "triangle": return 0.5 * s.b * s.h;
    default: {
      const unreachable: never = s;
      return unreachable;
    }
  }
}
const all: Shape[] = [{ kind: "circle", r: 1 }, { kind: "rect", w: 3, h: 4 }, { kind: "triangle", b: 6, h: 2 }];
console.log(all.map((s) => `${s.kind}=${area(s).toFixed(2)}`).join(" "));

✅ Verified output

circle=3.14 rect=12.00 triangle=6.00
Typed async code

async functions return Promise<T>; the awaited value keeps its type. Promise.all on a typed tuple gives a typed tuple back.

interface Weather { city: string; tempC: number; }
const wait = (ms: number) => new Promise<void>((ok) => setTimeout(ok, ms));
async function fetchWeather(city: string): Promise<Weather> {
  await wait(100);
  return { city, tempC: city.length * 4 };
}
async function main(): Promise<void> {
  const [a, b] = await Promise.all([fetchWeather("Pune"), fetchWeather("Hyderabad")]);
  console.log(`${a.city} ${a.tempC}C, ${b.city} ${b.tempC}C`);
}
main();

✅ Verified output

Pune 16C, Hyderabad 36C

🛠️ Set up and verify

  1. Install
    npm install -g typescript
    npm install -g typescript
    npm install -g typescript
  2. Editor: Visual Studio Code with ESLint, Prettier (TypeScript support is built into VS Code).
  3. Create hello.ts
    const who: string = 'GayaGnan';
    console.log(`Hello, ${who}!`);
  4. Run it and check the version
    tsc hello.ts && node hello.js
    tsc --version
  5. Health check: paste what your terminal printed.

Install one language at a time. These commands only install or print versions; nothing here deletes files. Versions change: check the official page and note the version you installed.

🧭 The 14-lab path

  • 00 · Setup and verify — install the runtime and editor, run hello world, print the version, fix PATH
  • 01 · Syntax and trace — follow each line and the value of every variable
  • 02 · Logic — conditionals and decision trees
  • 03 · Loops — trace tables and loop challenges
  • 04 · Functions — break problems down and test each piece
  • 05 · Data structures — lists, maps, stacks, queues and trees you can see
  • 06 · Debugging — bug cases with a hint ladder
  • 07 · Algorithms — search, sort and Big-O comparison
  • 08 · Files and data — read and write fixture files
  • 09 · API or database — talk to a mock API or a sandbox database
  • 10 · Testing — write tests and read failing assertions
  • 11 · Security — secure coding and dependency hygiene for this language 🧪 TypeScript Escape Room
  • 12 · Project — one portfolio mini-project
  • 13 · Assessment — quiz, coding test, rubric and an explain-your-answer prompt

📚 Modules

  1. primitive types
  2. unions
  3. interfaces
  4. generics
  5. narrowing
  6. typed functions
  7. async typing
  8. modules
  9. API schemas
  10. React props and state typing
  11. tests

🏗️ Mini-projects

  • Typed quiz engine
  • API client with validation
  • React student dashboard
  • Event workflow simulator

Projects use synthetic data only.