Free learning resource

Source code & resources

Every code example from TypeScript Mastery: From Foundations to Advanced Types — free to read, copy and run. No sign-up, no catch. If you found this from one of my courses, welcome; take the code and keep building.

Source code

Code from every lesson

33 examples, in lesson order.

1. Hello World and console.log TypeScript

// Welcome our hero to the dungeon
console.log("Adventurer enters the dungeon!");

// Announce the first quest
console.log("Quest: Defeat the slime king.");

// Set the mood
console.log("The torches flicker softly.");

2. Declaring Variables with let and const TypeScript

const heroName: string = "Aerith";
const maxLevel: number = 99;
const isLegendary: boolean = true;

console.log("Hero:", heroName);
console.log("Max level:", maxLevel);
console.log("Legendary:", isLegendary);

3. Primitive Types: number, string, boolean TypeScript

// Hero stats use the number type
let heroHp: number = 100;
let critChance: number = 0.25;
let goldFound: number = 1337;

// Math works on both forms
let totalDamage: number = 47 + 13;
let healPercent: number = critChance * 100;

console.log("Hero HP: " + heroHp);
console.log("Total damage: " + totalDamage);
console.log("Crit chance: " + healPercent + "%");
console.log("Gold found: " + goldFound);

4. Type Inference vs Explicit Annotations TypeScript

const heroName = "Nova";
const heroLevel = 50;
const isLegendary = true;

console.log("Name:", heroName);
console.log("Level:", heroLevel);
console.log("Legend:", isLegendary);

5. The any, unknown, and never Types TypeScript

let heroLoot: any = "Iron Sword";
console.log(heroLoot.toUpperCase());

heroLoot = 9001;
console.log(heroLoot.toFixed(2));

heroLoot = true;
console.log(heroLoot * 50);

6. Arithmetic, Comparison, and Logical Operators TypeScript

const heroAttack: number = 42;
const enemyDefense: number = 15;

// Damage from attack minus defense
const damage: number = heroAttack - enemyDefense;

// Bonus gold from clearing the room
const baseGold: number = 100;
const roomCount: number = 4;
const totalGold: number = baseGold * roomCount;

console.log("Damage dealt: " + damage);
console.log("Gold earned: " + totalGold);

7. if, else if, and else Statements TypeScript

let heroHp: number = 25;
const maxHp: number = 100;

if (heroHp < 30) {
  console.log("Low HP! Use a potion!");
}

console.log(`Hero HP: ${heroHp} / ${maxHp}`);

8. The Ternary Operator and Short-Circuit Evaluation TypeScript

const heroLevel: number = 47;

const rank: string =
    heroLevel >= 50 ? "Legendary" : "Veteran";

console.log("Hero status check!");
console.log(`Level: ${heroLevel}`);
console.log(`Rank assigned: ${rank}`);

const xp: number = 9999;
const upgrade: string =
    xp >= 10000 ? "Ready" : "Grinding";

console.log(`XP progress: ${upgrade}`);

9. switch Statements and Exhaustiveness Checking TypeScript

const enemy = "dragon";

switch (enemy) {
  case "goblin":
    console.log("Easy loot incoming!");
    break;
  case "dragon":
    console.log("Dragon spotted! Brace up!");
    break;
  case "lich":
    console.log("Undead boss appeared!");
    break;
  default:
    console.log("Unknown foe nearby.");
}

10. Truthy, Falsy, and Equality Pitfalls TypeScript

const falsy: unknown[] = [
  false,
  0,
  "",
  null,
  undefined,
  NaN,
];
const names: string[] = [
  "false",
  "zero",
  "empty string",
  "null",
  "undefined",
  "NaN",
];
for (let i = 0; i < falsy.length; i++) {
  if (falsy[i]) {
    console.log(names[i] + " is truthy");
  } else {
    console.log(names[i] + " is falsy");
  }
}

11. The for and while Loops TypeScript

// Track XP gained from ten battles
let totalXp: number = 0;

for (let i: number = 1; i <= 10; i++) {
    totalXp += i;
}

console.log("Battle marathon complete!");
console.log(`Total XP: ${totalXp}`);

12. Arrays and Their Methods TypeScript

// Two ways to type an array of numbers
const spellDamages: number[] = [25, 40, 60];
const spellNames: Array<string> = [
    "Fireball",
    "Ice Lance",
    "Thunder"
];

console.log("Spell roster ready");
console.log(spellDamages);
console.log(spellNames);

13. The for-of and for-in Loops TypeScript

const damageRolls: number[] = [
    12, 8, 25, 17, 6,
];

let total: number = 0;

for (const roll of damageRolls) {
    total = total + roll;
    console.log(`Hit for ${roll}!`);
}

console.log(`Total damage: ${total}`);

14. Tuples and Readonly Arrays TypeScript

const hero: [string, number] = ["Cloud", 50];

console.log("Hero name: " + hero[0]);
console.log("Hero level: " + hero[1]);

const boss: [string, number] = ["Sephiroth", 99];

console.log("Boss name: " + boss[0]);
console.log("Boss level: " + boss[1]);

15. Objects, Maps, and Sets TypeScript

type HeroStats = {
    hp: number;
    mp: number;
    level: number;
};

const aria: HeroStats = {
    hp: 240,
    mp: 80,
    level: 12,
};

console.log("Aria HP:", aria.hp);
console.log("Aria MP:", aria.mp);
console.log("Aria Level:", aria.level);

16. Destructuring and the Spread Operator TypeScript

interface Hero {
  name: string;
  hp: number;
  mp: number;
}

const mia: Hero = {
  name: "Mia",
  hp: 100,
  mp: 50
};

const { name, hp, mp } = mia;

console.log(`Hero ${name} stands ready!`);
console.log(`Health ${hp}. Mana ${mp}.`);

17. Function Declarations and Arrow Functions TypeScript

function addDamage(
    base: number,
    crit: number
): number {
    return base + crit;
}

const swordHit: number = addDamage(25, 15);
const bowShot: number = addDamage(18, 9);

console.log(
    "Sword strike dealt " + swordHit + " damage!"
);
console.log(
    "Bow shot dealt " + bowShot + " damage!"
);

18. Optional, Default, and Rest Parameters TypeScript

function announceQuest(
  questName: string,
  reward?: number
): void {
  if (reward !== undefined) {
    console.log(
      `${questName} pays ${reward} gold!`
    );
  } else {
    console.log(`${questName} accepted.`);
  }
}

announceQuest("Slay the Dragon", 500);
announceQuest("Find the Lost Cat");

19. Function Types and Callback Signatures TypeScript

// A function from number to number
type NumberTransformer = (n: number) => number;

// A function from number to string
type Stringifier = (n: number) => string;

// A function deciding yes or no
type Predicate = (n: number) => boolean;

20. Type Aliases and Interfaces TypeScript

type Hero = {
    codename: string;
    powerLevel: number;
    canFly: boolean;
};

const baker: Hero = {
    codename: "Head Baker",
    powerLevel: 9001,
    canFly: true,
};

console.log(
    `${baker.codename} hits ${baker.powerLevel}!`
);

21. Union and Intersection Types TypeScript

type ScoreInput = string | number;

function showScore(input: ScoreInput): void {
  if (typeof input === "string") {
    console.log("Name: " + input.toUpperCase());
  } else {
    const squared = input * input;
    console.log("Power level: " + squared);
  }
}

showScore("editor");
showScore(12);

22. Literal Types and const Assertions TypeScript

const heroName: "Falcon" = "Falcon";
console.log(`Hero summoned: ${heroName}`);

const startLevel: 1 = 1;
console.log(`Begin at level ${startLevel}.`);

const isAlive: true = true;
console.log(`Alive status: ${isAlive}`);

23. Promises and the async/await Pattern TypeScript

function dropLoot(): Promise<string> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("Legendary Sword!");
        }, 500);
    });
}

dropLoot().then((loot: string) => {
    console.log(`You found: ${loot}`);
});

24. Concurrency with Promise.all, allSettled, and Worker Threads TypeScript

function openChest(name: string,
  ms: number): Promise<string> {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`${name} dropped loot!`);
    }, ms);
  });
}

async function lootRun(): Promise<void> {
  const drops = await Promise.all([
    openChest("Dragon", 100),
    openChest("Lich", 80),
    openChest("Kraken", 60),
  ]);
  drops.forEach(d => console.log(d));
}

lootRun();

25. Generators and Lazy Iteration TypeScript

function* questQueue(): Generator<string> {
    yield "Slay the river troll";
    yield "Find the lost amulet";
    yield "Escort the merchant";
}

const quests = questQueue();
console.log(quests.next().value);
console.log(quests.next().value);
console.log(quests.next().value);
console.log(quests.next().done);

26. map, filter, and reduce over Loops TypeScript

type Order = {
  id: string;
  total: number;
  paid: boolean;
};

const orders: Order[] = [
  { id: "Q1", total: 50, paid: true },
  { id: "Q2", total: 80, paid: false },
  { id: "Q3", total: 120, paid: true },
  { id: "Q4", total: 200, paid: true },
];

27. Higher-Order Functions and Closures TypeScript

function applyBuff(
  baseDamage: number,
  buff: (n: number) => number
): number {
  return buff(baseDamage);
}

const critical = (dmg: number): number => dmg * 2;
const elemental = (dmg: number): number => dmg + 15;

const slash: number = 40;
console.log("Crit hit:", applyBuff(slash, critical));
console.log("Fire hit:", applyBuff(slash, elemental));

28. Generics: Functions and Classes That Work with Any Type TypeScript

function echo<T>(value: T): T {
  return value;
}

const hp: number = echo<number>(150);
const hero: string = echo<string>("Parcel");
const ready: boolean = echo<boolean>(true);

console.log("Echoed HP:", hp);
console.log("Echoed hero:", hero);
console.log("Ready to fight?", ready);

29. Generic Constraints and Conditional Types TypeScript

interface Named {
  name: string;
}

function announce<T extends Named>(
  item: T
): void {
  console.log("Behold the " + item.name);
}

const sword = {
  name: "Frostmourne",
  damage: 95,
};

const potion = {
  name: "Elixir",
  heals: 150,
};

announce(sword);
announce(potion);

30. Utility Types: Partial, Required, Pick, Omit, Record TypeScript

interface Hero {
  id: number;
  name: string;
  level: number;
  hp: number;
  password: string;
  guild?: string;
}

31. Error Handling with try/catch and the Result Pattern TypeScript

function castFireball(
  mana: number,
  cost: number
): number {
  if (mana < cost) {
    throw new Error("Not enough mana!");
  }
  return mana - cost;
}

try {
  const left = castFireball(20, 50);
  console.log("Mana left:", left);
} catch (err) {
  console.log("Spell fizzled!");
}

32. Classes, Data Classes, and Readonly Records TypeScript

class Warrior {
  constructor(
    public name: string,
    public level: number
  ) {}
}

const aria = new Warrior("Aria", 47);
console.log(aria.name + ", level " + aria.level);

33. Decorators and Metadata for Cross-Cutting Concerns TypeScript

type Ctor = new (...a: unknown[]) => object;

function logged<T extends Ctor>(
  target: T,
  ctx: ClassDecoratorContext
): T {
  return class extends target {
    constructor(...args: unknown[]) {
      super(...args);
      console.log(`Summoned ${ctx.name}!`);
    }
  } as T;
}

@logged
class Barista {
  constructor(public name: string) {}
}

const sara = new Barista("Sara");
const tom = new Barista("Tom");