Classes
Class members and accessors, access modifiers, parameter properties, inheritance, and abstract classes.
12 questions
JuniorTheoryVery commonWhat do public, private, and protected do in a class?
What do public, private, and protected do in a class?
They control member visibility. public, the default, is accessible everywhere. private is accessible only within the declaring class. protected is accessible within the class and its subclasses. These modifiers are enforced only at compile time and are erased from the emitted JavaScript, so for genuine runtime privacy you must use a #private field instead.
Common mistakes
- ✗Assuming
privatehides a member at runtime — it is only a compile-time check and is erased - ✗Swapping
privateandprotected(subclass access belongs toprotected) - ✗Forgetting
publicis the default when no modifier is written
Follow-up questions
- →How does a
#privatefield differ from aprivatemodifier? - →Can a subclass read a
protectedmember of its base class?
JuniorTheoryVery commonWhat member features do TypeScript classes support?
What member features do TypeScript classes support?
A class supports typed instance fields, a constructor, methods, readonly fields settable only in their declaration or the constructor, static members that belong to the class itself rather than instances, and get/set accessors that control how a property is read or written. On top of ES2015 classes, TypeScript adds field types, access modifiers, and abstract.
Common mistakes
- ✗Thinking
staticmembers are accessed through an instance rather than the class - ✗Believing
readonlycan be assigned anywhere instead of only at declaration or in the constructor - ✗Assuming TypeScript lacks class expressions or iterators (it is a superset of JS)
Follow-up questions
- →What is the difference between an instance member and a
staticmember? - →When would you reach for a
get/setaccessor instead of a plain field?
MiddleTheoryVery commonHow does class inheritance work in TypeScript?
How does class inheritance work in TypeScript?
class B extends A makes B inherit A's members. A subclass constructor must call super(...) before using this. Methods can be overridden, optionally marked override, and super.method() calls the base version. A protected member is reachable in subclasses while a private one is not. TypeScript allows single inheritance only — one base class — so use interfaces for multiple contracts.
Common mistakes
- ✗Using
thisin a subclass constructor before callingsuper(...) - ✗Believing
privatemembers are inherited and usable in a subclass (onlyprotectedare) - ✗Expecting multiple class inheritance — TypeScript allows only one base class
Follow-up questions
- →What does the
overridekeyword add beyond a plain method redefinition? - →How do you give a class several contracts without multiple inheritance?
JuniorTheoryCommonWhat are get and set accessors in a TypeScript class?
What are get and set accessors in a TypeScript class?
Accessors intercept reading and writing a property with method bodies while callers still use plain property syntax. A get name() runs when the property is read and returns the value; a set name(v) runs when it is assigned and receives the new value. They let you add validation, computation, or logging behind obj.name. A property with only a getter is effectively read-only.
Common mistakes
- ✗Calling an accessor with parentheses —
obj.name, notobj.name() - ✗Swapping which keyword fires on read versus write (
getreads,setwrites) - ✗Forgetting that a getter without a setter makes the property read-only
Follow-up questions
- →How would you make a computed property that has no backing field?
- →What happens if you define a getter but no matching setter?
JuniorTheoryCommonWhat does the readonly modifier do on a property?
What does the readonly modifier do on a property?
readonly marks a property as assignable only once — at declaration or inside the constructor — after which the compiler rejects any reassignment. It is a compile-time check only and is erased from the emitted JavaScript, so it gives no runtime immutability. It pins the binding, not the contents: a readonly array can still be mutated with push.
Common mistakes
- ✗Expecting
readonlyto prevent mutation at runtime — it is erased after compilation - ✗Thinking a
readonlyarray's elements cannot be changed (only the binding is locked) - ✗Believing a
readonlyfield can never be set, rather than set once in the constructor
Follow-up questions
- →How does the
Readonly<T>utility type relate to thereadonlymodifier? - →Why can you still call
pushon areadonlyarray property?
JuniorTheoryCommonHow does a static member differ from an instance member?
How does a static member differ from an instance member?
A static member belongs to the class itself: it exists once and is reached as ClassName.member, never through an instance. An instance member is created per object by new and reached through this. Inside a static method this is the class.
Common mistakes
- ✗Reaching a
staticmember through an instance instead of through the class - ✗Thinking each instance gets its own copy of a
staticmember - ✗Expecting
thisinside astaticmethod to point at an instance
Follow-up questions
- →How is a
staticmember reached from a subclass that extends the class? - →When is the initializer of a
staticfield evaluated?
MiddleTheoryCommonWhat is an abstract class and when do you use it?
What is an abstract class and when do you use it?
An abstract class is a base blueprint that cannot be instantiated directly. Its abstract methods declare a signature with no body that every subclass must implement, but it can also hold concrete methods, fields, and a constructor shared by subclasses. Use one to share implementation while forcing subclasses to fill in specifics. Unlike an interface, an abstract class can carry implementation and state.
Common mistakes
- ✗Trying to instantiate an abstract class directly with
new - ✗Thinking an
abstractmethod may have a body (it is signature-only) - ✗Confusing it with an interface — an abstract class can hold implementation and state
Follow-up questions
- →When would you choose an abstract class over an interface?
- →What happens if a subclass leaves an
abstractmethod unimplemented?
MiddleTheoryCommonHow does a #private field differ from the private modifier?
How does a #private field differ from the private modifier?
private is TypeScript-only: the checker enforces then erases it, so the property survives in the emitted JavaScript, readable via obj['x']. #x is an ECMAScript field the engine enforces — outside code cannot name it or see it in Object.keys.
Common mistakes
- ✗Believing
privatehides the property at runtime — it is erased and still readable via a cast - ✗Assuming
#xcompiles down to an ordinary property namedxthat outside code can reach - ✗Expecting a
#privatefield to show up inObject.keysorJSON.stringifyoutput
Follow-up questions
- →How can you check whether an object carries a given
#privatefield? - →Why can a subclass not read a
#privatefield of its base class?
JuniorTheoryOccasionalWhat are parameter properties in a TypeScript constructor?
What are parameter properties in a TypeScript constructor?
A parameter property is a constructor parameter prefixed with an access modifier (public, private, protected) and/or readonly. TypeScript then automatically declares a class field of the same name and assigns the argument to it, so constructor(private name: string) {} replaces a separate field declaration plus this.name = name. It is shorthand that removes boilerplate.
Common mistakes
- ✗Thinking a plain typed parameter becomes a field — a modifier or
readonlyis required - ✗Forgetting parameter properties only work on the
constructor, not on other methods - ✗Still writing the redundant
this.name = nameassignment alongside the modifier
Follow-up questions
- →What happens if you omit the modifier on a constructor parameter?
- →Can you combine
readonlywithprivateon the same parameter property?
MiddleTheoryOccasionalWhat does private readonly add over a plain readonly field?
What does private readonly add over a plain readonly field?
Visibility. The modifiers are orthogonal: readonly governs mutability, private visibility. A plain readonly field is assign-once yet publicly readable; private readonly hides it from outside. Both are compile-time checks, erased at build.
Common mistakes
- ✗Thinking
readonlyalso hides the field from outside the class - ✗Believing
privaterelaxesreadonlyinside the declaring class - ✗Expecting either modifier to survive into the emitted JavaScript
Follow-up questions
- →Where may a
readonlyfield legally be assigned? - →How would you expose a
private readonlyfield to callers without letting them write it?
MiddleTheoryOccasionalHow deep is the immutability that readonly gives a property?
How deep is the immutability that readonly gives a property?
One level. readonly locks the binding — the property cannot be reassigned — but says nothing about the object it points at, so readonly items: string[] still allows items.push(x). Readonly<T> is shallow too; real depth needs a recursive type.
Common mistakes
- ✗Expecting
readonlyto stoppushon areadonlyarray property - ✗Assuming
Readonly<T>is deep rather than one level of keys - ✗Confusing the compile-time check with a runtime
Object.freeze
Follow-up questions
- →How does
readonly string[]differ fromreadonly items: string[]? - →How would you express a deeply immutable type for a nested object?
SeniorTheoryOccasionalWhat does the definite assignment assertion in name!: string silence?
What does the definite assignment assertion in name!: string silence?
It silences strictPropertyInitialization, the check that a non-optional field is assigned in its declaration or constructor. ! emits no runtime check and no initializer, so the field can still be undefined while its type promises string.
Common mistakes
- ✗Thinking
!makes the compiler emit a runtime guard or a default initializer - ✗Believing a field marked
!can never beundefinedat runtime - ✗Reaching for
!instead of initializing the field or marking it optional
Follow-up questions
- →Which compiler flag turns
strictPropertyInitializationon? - →What safer alternatives exist for a field assigned outside the constructor?