Type System
TypeScript’s type system catches errors at compile time without changing how your code runs.
Type Inference
TypeScript infers types from values. You don’t need to annotate everything.
let name = "Alice"; // inferred as string
let count = 42; // inferred as number
let items = [1, 2, 3]; // inferred as number[]
Tip: Let TypeScript infer when it can. Only add annotations when the compiler can’t figure it out or when you want to be explicit about a public API.
Type Annotations
Explicitly declare types when inference isn’t enough:
function greet(name: string): string {
return "Hello, " + name;
}
greet("Alice"); // OK
greet(42); // Error: Argument of type 'number' is not assignable to parameter of type 'string'
Gotcha: Over-annotating makes code verbose. If a variable is initialized on the same line, the annotation is usually redundant:
let x: number = 5is the same aslet x = 5.
Primitive Types
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let missing: null = null;
let notDefined: undefined = undefined;
Arrays and Tuples
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10]; // fixed length, fixed types per position
Union Types
A value that can be one of several types:
type ID = string | number;
function printId(id: ID) {
if (typeof id === "string") {
console.log(id.toUpperCase()); // TypeScript knows it's a string here
} else {
console.log(id); // TypeScript knows it's a number here
}
}
Intersection Types
Combine multiple types into one:
type User = { name: string; age: number };
type DBRecord = { id: string };
type UserRecord = User & DBRecord;
// UserRecord has: name, age, and id
Structural Typing
TypeScript checks structure, not names. If it has the right shape, it’s compatible.
interface Duck {
walk: () => void;
quack: () => void;
}
let bird = {
walk: () => console.log("walking"),
quack: () => console.log("quacking"),
fly: () => console.log("flying"), // extra property is fine
};
let duck: Duck = bird; // OK - bird has walk and quack
Gotcha: Structural typing means extra properties are allowed when assigning variables. But object literals get stricter checking - TypeScript flags unknown properties on them.