Lab 01: Hello World & Basics

Objective

Set up TypeScript, compile .ts files to JavaScript, understand the TypeScript compiler (tsc), and write your first typed program.

Background

TypeScript is a statically typed superset of JavaScript created by Microsoft. Every valid JavaScript file is valid TypeScript — TypeScript adds optional type annotations that are erased at compile time. The result is plain JavaScript that runs anywhere JS runs. TypeScript's killer feature: it catches bugs at compile time that JavaScript would only reveal at runtime.

Time

20 minutes

Prerequisites

  • Basic JavaScript knowledge

Tools

  • Docker image: zchencow/innozverse-ts:latest (Node 20 + TypeScript 5.x)

  • Run: docker run --rm -it zchencow/innozverse-ts:latest


Lab Instructions

Step 1: Your First TypeScript File

Run with ts-node:

💡 TypeScript type annotations are written as : TypeName after a variable or parameter. They're completely erased when compiled to JavaScript — zero runtime overhead. The TypeScript compiler (tsc) checks types statically before any code runs.

📸 Verified Output:


Step 2: Primitive Types

💡 unknown is safer than any — with any, TypeScript trusts you completely (no checking). With unknown, TypeScript requires you to narrow the type before using it. Use unknown for values from external sources (JSON, user input, API responses) and narrow with typeof, instanceof, or type guards.

📸 Verified Output:


Step 3: Arrays & Tuples

💡 Tuples encode position-dependent meaning. [number, number] for a point is cleaner than {x: number, y: number} for math operations, and cleaner than just number[] (which could be any length). React's useState returns a tuple: [state, setState] — that's why you destructure it.

📸 Verified Output:


Step 4: Object Types & Interfaces

💡 interface vs type: Both define shapes. Use interface for object shapes (it's extendable with extends). Use type for unions, intersections, and complex types. A key difference: interface can be "declaration merged" — two interface User declarations merge into one. type cannot be reopened.

📸 Verified Output:


Step 5: Type Aliases

💡 String literal unions ("active" | "inactive") are one of TypeScript's most useful features. They're like enums but lighter — you get autocomplete, type checking, and exhaustiveness checking in switch statements. Use them for status fields, directions, HTTP methods, and any closed set of string values.

📸 Verified Output:


Step 6: tsconfig.json Overview

💡 strict: true enables 8+ strict checks with one flag. The most important: strictNullChecks makes null and undefined their own types — a string variable can't be null unless you write string | null. This eliminates entire classes of "Cannot read property of null" runtime errors.

📸 Verified Output:


Step 7: Compiling TypeScript

💡 ts-node compiles and runs TypeScript in one step — perfect for learning and scripting. For production, compile with tsc first (produces .js files), then run with node. ts-node is slower (compiles on every run) but eliminates the build step during development.

📸 Verified Output:


Step 8: Complete — Type-Safe Calculator

💡 Record<K, V> is a built-in utility type that creates an object type with keys of type K and values of type V. Record<Operation, string> means "an object where every Operation key must be present with a string value." This gives exhaustiveness checking — if you add a new Operation, TypeScript errors until you add it to the Record.

📸 Verified Output:


Verification

Summary

TypeScript adds a powerful type system on top of JavaScript. You've covered primitive types, inference, arrays, tuples, interfaces, type aliases, literal unions, strict mode, and a complete type-safe calculator. The type annotations disappear at runtime — you get the benefits of static typing with zero runtime cost.

Further Reading

Last updated