Classes
Access modifiers, readonly, parameter properties and implements.
Classes bundle state with the operations allowed on it. TypeScript adds
compile-time locks — private, protected, readonly — plus a way to
promise an interface with implements. Interviewers check you know the
locks vanish at runtime.
Real-life situation
A bank account hides its balance behind deposit and total methods so
no caller can set it directly. Marking the owner readonly stops
reassignment in the editor — but the emitted JavaScript assigns happily,
which the runner below proves. The lock is a promise between developers,
not a vault.
Visual
Try it
Checked with TypeScript 6.0.3, strict mode
class BankAccount {
private balance: number;
readonly owner: string;
constructor(owner: string, start: number) {
this.owner = owner;
this.balance = start;
}
deposit(amount: number): void {
this.balance = this.balance + amount;
}
total(): number {
return this.balance;
}
}
const mine = new BankAccount("sam", 100);
mine.deposit(50);
console.log(mine.owner + " has " + mine.total());
mine.owner = "jo";
console.log(mine.total());Compiler not loaded. Check or Run loads it here (about 9 MB) — nothing downloads until you do.
Try removing the mine.owner = "jo" line — clean. Then try reading
mine.balance from outside: private fails the same way. Parameter
properties (constructor(private balance: number)) declare and assign
in one stroke, and abstract classes sketch shared behavior subclasses
must complete. For this behavior itself, revisit
this in the JavaScript topic.
Will it compile? — decide first, then reveal.
class Vault {
private code = 1234;
}
const vault = new Vault();
console.log(vault.code);Interview questions
How do you declare a class with typed fields in TypeScript?basic
You list each field with its type, like name: string, and assign them in the constructor or at declaration. The compiler requires every non-optional field to be definitely assigned before construction finishes. Declare the shape up front so readers see the state at a glance. Use constructor parameter properties like constructor(public name: string) as a shorthand when you want declaration and assignment in one line.
Interviewers also ask
- What shorthand declares and assigns a field at once?
How does the constructor work with types?basic
The constructor takes typed parameters and initializes the instance, like constructor(name: string) { this.name = name }. Its parameters follow the same rules as functions — required first, optionals and defaults last. The checker verifies every field is set on all paths through the constructor. Keep construction simple: validate and assign, and move complex creation into static factory methods that stay easy to type and test.
Interviewers also ask
- Who checks that every field gets assigned?
What do public, private, and protected mean?basic
They control where a member can be used: public anywhere, protected inside the class and its subclasses, and private only inside the declaring class. The compiler rejects out-of-scope access at build time, which documents your intended surface area. Remember it is a static guard — emitted JavaScript historically still exposes the field at runtime. For hard runtime privacy, use JavaScript #private fields alongside the type-level modifiers.
Interviewers also ask
- Do private fields stay private at runtime?
How does readonly work on class fields?basic
Marking a field readonly lets the constructor assign it once and forbids later writes, like readonly id: string. It suits identifiers and injected dependencies that must never change. The compiler enforces the rule statically; plain JavaScript output does not freeze the value. Combine readonly with constructor shorthand — constructor(readonly id: string) — for immutable state with minimal boilerplate.
Interviewers also ask
- Where is the only place a readonly field can be set?
How does implements work with a class?intermediate
You declare class User implements Named { name: string } to promise the class satisfies the Named shape, and the compiler verifies every member exists with a compatible type. It only checks the contract — no code is inherited, unlike extends. Use implements to keep classes honest against shared interfaces while leaving the implementation free. If the interface changes, every implementing class is flagged at once.
Interviewers also ask
- How is implements different from extends?
How does extends work for class inheritance?intermediate
A subclass with class Admin extends User inherits fields and methods and can override them, calling super() to run the parent constructor first. The checker ensures overrides stay compatible — you cannot widen parameter types or drop required members. Keep hierarchies shallow: deep chains are hard to type and test. Favor composition over inheritance when the relationship is has-a rather than is-a.
Interviewers also ask
- What must a subclass constructor call first?
What is an abstract class?intermediate
A base class marked abstract that cannot be instantiated directly — it exists to be extended. It can declare abstract methods with no body, which each concrete subclass must implement. You use it when subclasses share real logic plus required holes, like a Shape base with a shared move method and an abstract area. For pure contracts with no shared code, prefer an interface instead.
Interviewers also ask
- When is an interface a better fit than an abstract class?
How do getters, setters, and static members work?intermediate
Getters and setters expose computed access like get fullName() while storing simpler fields underneath — callers read a property, you run a function. Annotate the getter's return and the setter's parameter so both stay consistent. static members belong to the class itself, like User.nextId, and are accessed without new. Use statics for factories and shared counters, and accessors when derived state must stay in sync.
Interviewers also ask
- How do you access a static member?
Key takeaways
privateandreadonlyare editor promises — the emit ignores them.implementschecks the class against an interface at declaration time.- Parameter properties and
abstractremove whole lines of boilerplate.
Runner helpers
sleep(ms)waits;fakeFetch(url)returns deterministic sample data. TypeScript is stripped before running; imports and exports are not available in the sandbox.