01 - TypeScript Basics

What is TypeScript?

TypeScript is JavaScript with types. It catches errors at compile time (before your code runs) instead of at runtime. All valid JavaScript is valid TypeScript — you're just adding type annotations on top.

// JavaScript — no errors until you run it
let name = "John";
name = 42;  // no error... until something breaks later

// TypeScript — catches it immediately
let name: string = "John";
name = 42;  // ❌ compile error: Type 'number' is not assignable to type 'string'

Basic Types

let name: string = "John";
let age: number = 30;
let active: boolean = true;
let items: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10];  // fixed-length array with specific types
let anything: any = "flexible";    // disables type checking — avoid when possible
let unknown: unknown = "safer";    // like any, but forces you to check the type before using

Type Inference

You don't always need to write types — TypeScript infers them from the value:

let message = "Hello";  // inferred as string
let count = 42;         // inferred as number
let active = true;      // inferred as boolean

message = 123;  // ❌ error — TypeScript knows it's a string

Rule of thumb: let TypeScript infer when the type is obvious. Add annotations when it's not.

Arrays

let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];  // alternative syntax, same thing

numbers.push("hello");  // ❌ error — only numbers allowed

Objects

let person: { name: string; age: number } = {
  name: "Alice",
  age: 25
};

person.email = "a@b.com";  // ❌ error — 'email' doesn't exist on this type

Inline object types get verbose fast — that's why interfaces and type aliases exist (lesson 03).

any vs unknown

// any — disables ALL type checking (dangerous)
let a: any = "hello";
a.toFixed();  // no error at compile time, but crashes at runtime

// unknown — must check the type before using (safe)
let b: unknown = "hello";
b.toFixed();           // ❌ error — can't use without checking first
if (typeof b === "string") {
  b.toUpperCase();     // ✅ now TypeScript knows it's a string
}

Prefer unknown over any when you don't know the type.

null and undefined

let nullable: string | null = null;       // explicitly can be null
let optional: string | undefined = undefined;  // explicitly can be undefined

// Strict null checks — TypeScript won't let you use a possibly-null value
function greet(name: string | null) {
  console.log(name.toUpperCase());   // ❌ error — name might be null
  console.log(name?.toUpperCase());  // ✅ optional chaining — safe
}

Key Takeaways

  • TypeScript = JavaScript + types
  • Types catch errors before your code runs
  • Let TypeScript infer types when obvious
  • Avoid any — use unknown if you don't know the type
  • ? makes properties optional, ?. is optional chaining for safe access