Object Types and Classes
Our tracker's central value is a task: an object with an id, a title, a done flag and maybe a due date. Describing that shape once, and having the compiler hold every function to it, is where TypeScript starts to pay for itself.
The rule
An object type lists each property and its type; a class is also a type.
Write an object type with braces, listing each property name and its type:
type Task = {
readonly id: number; // cannot be reassigned
title: string;
done: boolean;
due?: string; // optional: may be left out
};
const t: Task = { id: 1, title: "Buy milk", done: false };
t.done = true; // fine
t.id = 2; // error: id is a read-only propertyThree rules to know:
- Required by default. Leaving out
titleis an error: the property is missing. ?makes a property optional.duemay be absent, so reading it gives astringorundefined.- Excess property check. When you write a fresh object literal where a
Taskis expected, TypeScript also flags properties the type does not mention, such aspriority: 1. Those are usually typos.
You can also name an object shape with an interface, which the final section covers in depth. For now, type Task = {...} and interface Task {...} both describe the same shape.
Avoid the loose types Object, object and {} for data like this. They say almost nothing: you cannot read .title from a value typed object.
Classes. A class declaration creates two things: a constructor you call at runtime, and a type with the same name describing its instances.
class TaskList {
tasks: Task[] = [];
add(task: Task): void { this.tasks.push(task); }
}
const inbox: TaskList = new TaskList(); // TaskList used as a typeThe shortcut
For every property, ask two questions: "Is it always there?" (no → ?) and "Can it change after creation?" (no → readonly). Everything else is a plain name: type.
id
Always there, never changes:
readonly id: number.
The trap: readonly is checked at compile time only. It does not freeze the object at runtime.
Drills
Answer fast — trust the rule.
A Task type requires title. What happens with const t: Task = { id: 1, done: false };?
How do you mark due as a property that may be left out?
Using the TaskList class above, which line is valid?
Why does { id: 1, title: "x", done: false, prio: 2 } fail when assigned directly to a Task?
Remember
- An object type lists each property and its type; a class is also a type.
- Ask "always there?" for
?and "can it change?" forreadonly. - Trap:
readonlyand other types vanish at runtime; they do not freeze objects.
