/* sample-app.ts: a complete, commented TypeScript file. Free sample from 99helpers.com/file-types/ts Run it: node sample-app.ts (Node.js 22.18+ or 23.6+ strip the types) npx tsx sample-app.ts (any current Node.js) deno run sample-app.ts or bun sample-app.ts Check it: npx tsc --noEmit sample-app.ts */ // 1. Type annotations: a colon after a name says what it may hold. // The compiler checks them; they are removed before the code runs. const shopName: string = "Ada's Café"; let orderCount: number = 0; // 2. An interface describes the shape of an object. interface Product { readonly id: string; name: string; priceCents: number; // whole cents avoid floating-point rounding tags?: readonly string[]; // ? marks an optional property } // 3. A union of string literals: only these three values are allowed. type Status = "pending" | "paid" | "shipped"; // 4. A type alias for an object built from other types. type Order = { id: number; items: Array<{ product: Product; quantity: number }>; status: Status; }; // 5. A typed function: parameter types and a return type. function lineTotal(product: Product, quantity: number): number { return product.priceCents * quantity; } // 6. Generics: lets one function work with any type and keep it. function firstOrDefault(list: readonly T[], fallback: T): T { return list.length > 0 ? list[0] : fallback; } // 7. Narrowing: in each branch TypeScript knows which type the value has. function describe(value: string | number | null): string { if (value === null) return "nothing"; if (typeof value === "number") return `${value.toFixed(2)} (a number)`; return `"${value.toUpperCase()}" (a string)`; } // 8. `as const` keeps the exact values; `satisfies` checks them against // a type without widening them. Non-ASCII text is fine: files are UTF-8. const catalogue = [ { id: "tea", name: "Thé vert", priceCents: 350, tags: ["drink"] }, { id: "cake", name: "Crème brûlée", priceCents: 525 }, ] as const satisfies readonly Product[]; // 9. A class. `private` and `readonly` exist only for the compiler; // #totalCents is a real private field that JavaScript enforces. class Basket { #totalCents = 0; private readonly lines: string[] = []; add(product: Product, quantity = 1): this { this.#totalCents += lineTotal(product, quantity); this.lines.push(`${quantity} × ${product.name}`); return this; } get total(): string { return (this.#totalCents / 100).toFixed(2); } summary(): string { return this.lines.join(", "); } } // 10. Asynchronous code: the function promises to return an Order. async function markPaid(order: Order): Promise { await new Promise((resolve) => setTimeout(resolve, 10)); return { ...order, status: "paid" }; } // 11. Use it all. The output is the same in every runtime above. const basket = new Basket().add(catalogue[0], 2).add(catalogue[1]); const order: Order = { id: ++orderCount, items: catalogue.map((product) => ({ product, quantity: 1 })), status: "pending", }; console.log(`${shopName}: ${basket.summary()} = €${basket.total}`); console.log(describe(firstOrDefault(["first"], "none")), describe(9.5), describe(null)); markPaid(order).then((paid) => console.log(`Order ${paid.id} is ${paid.status}`));