TypeScript Basics · Type Aliases & any/unknown/never · Interface vs Type Alias · Classes in TypeScript
Add static types to JavaScript with TypeScript. Set up tsc, learn the primitive types, type inference, and the most useful tsconfig flags. Name complex types with type aliases, understand any (escape hatch), unknown (safe any), and never (impossible). Learn type narrowing. When to use interface and when to use type. Learn extends, declaration merging, and how structural typing decides assignability. Use TypeScript's class features: access modifiers, parameter properties, readonly, and abstract classes for shared base behavior.
What you'll learn
- 1Install TypeScript and write a minimal tsconfig.json
- 2Use the primitive types and literal types
- 3Rely on type inference, annotate when needed
- 4Run TS with tsx or compile with tsc
- 5Define type aliases for object and union types
- 6Distinguish any from unknown
- 7Use never for exhaustive switch checks
- 8Narrow with typeof, in, and discriminated unions
- 9Define object shapes with interface
- 10Extend interfaces and intersect types
- 11Explain structural ("duck") typing
- 12Pick interface for libraries, type for everything else
- 13Use access modifiers (public, private, protected)
- 14Take advantage of parameter properties
- 15Mark immutable fields with readonly
- 16Define abstract base classes
TypeScript Basics
Add static types to JavaScript with TypeScript. Set up tsc, learn the primitive types, type inference, and the most useful tsconfig flags.
1. Why TypeScript?
- Catch bugs at compile time, not at 3 AM
- Editors show real autocomplete and refactors
- Easier to navigate large codebases
- Industry standard for any non-trivial JS project
2. Setup
npm install --save-dev typescript tsx
npx tsc --init # creates tsconfig.json// tsconfig.json (key fields)
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"noEmit": true
}
}3. Primitive Types
let count: number = 0;
let name: string = "Alice";
let active: boolean = true;
let nothing: null = null;
let missing: undefined;
let ids: number[] = [1, 2, 3];
let pair: [string, number] = ["a", 1]; // tuple
// Type inference — let TS figure it out
const score = 100; // inferred as number
const greeting = "hello"; // inferred as string4. Literal Types & Unions
type Status = "pending" | "done" | "failed";
function setStatus(s: Status) { /* ... */ }
setStatus("done");
// setStatus("complete"); // error: not assignable
type ID = string | number; // unionType Aliases & any/unknown/never
Name complex types with type aliases, understand any (escape hatch), unknown (safe any), and never (impossible). Learn type narrowing.
1. Type Aliases
type User = {
id: number;
name: string;
email?: string; // optional
readonly createdAt: Date;
};
const u: User = { id: 1, name: "Alice", createdAt: new Date() };2. any vs unknown
// any: turn off type checking (use sparingly)
let a: any = JSON.parse(text);
a.whatever.does.not.error;
// unknown: safe — you must narrow before using
let u: unknown = JSON.parse(text);
if (typeof u === "object" && u !== null && "name" in u) {
console.log((u as { name: string }).name);
}Reach for unknown when you must, any almost never. unknown forces you to validate before use.
3. never & Exhaustive Checks
type Shape = { kind: "circle"; r: number } | { kind: "square"; side: number };
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.r ** 2;
case "square": return s.side ** 2;
default: {
const _exhaustive: never = s; // compile error if a case is missed
return _exhaustive;
}
}
}4. Narrowing
function describe(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
}
function take(item: { kind: "a"; x: number } | { kind: "b"; y: string }) {
if (item.kind === "a") item.x; // narrowed to first variant
else item.y; // narrowed to second
}Interface vs Type Alias
When to use interface and when to use type. Learn extends, declaration merging, and how structural typing decides assignability.
1. interface
interface User {
id: number;
name: string;
email?: string;
greet(): string;
}
const alice: User = {
id: 1,
name: "Alice",
greet() { return `Hi, ${this.name}`; },
};2. Extending
interface Animal { name: string }
interface Dog extends Animal { bark(): void }
// Type alias intersection — equivalent
type DogT = Animal & { bark(): void };3. interface vs type — When
| Need | Pick |
|---|---|
| Object shape, especially for public API | interface |
| Union, tuple, primitive alias | type |
| Need declaration merging | interface |
| Computed / mapped types | type |
Many teams pick one consistently and stick with it. Either works for most cases.
4. Structural Typing
interface Point { x: number; y: number }
function print(p: Point) { console.log(p.x, p.y); }
print({ x: 1, y: 2, color: "red" }); // OK — extra props allowed at call site
// TS asks "does it have the right shape?" — not "is it nominally a Point?"Classes in TypeScript
Use TypeScript's class features: access modifiers, parameter properties, readonly, and abstract classes for shared base behavior.
1. Basic Class
class BankAccount {
private balance: number = 0;
constructor(public readonly owner: string) {}
deposit(amount: number): void {
if (amount <= 0) throw new Error("amount must be positive");
this.balance += amount;
}
getBalance(): number {
return this.balance;
}
}
const acct = new BankAccount("Alice");
acct.deposit(100);
// acct.balance = 0; // error: privatepublic readonly owner: string is a parameter property — it both accepts the arg and assigns this.owner in one place.
2. Inheritance & abstract
abstract class Shape {
abstract area(): number;
describe(): string { return `area=${this.area()}`; }
}
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(5), new Rect(3, 4)];
shapes.forEach(s => console.log(s.describe()));3. implements an Interface
interface Serializable { toJSON(): string }
class Note implements Serializable {
constructor(public title: string, public body: string) {}
toJSON() { return JSON.stringify(this); }
}All lecture materials and example code are openly available on GitHub.
View on GitHub ↗Comments 0
No comments yet. Be the first.
Only members can comment.
Comments with ads, abuse, personal information or illegal content are hidden or removed. Comments are shown with your nickname. Privacy Policy