In TypeScript, what does the noImplicitOverride compiler option require, which class members does it apply to, and what bug is the override keyword designed to catch?
answer
- inheritance links members by name only
- state the intent, then it can be checked
- abstract and interface members are exempt
- the keyword is erased at emit
basics
~20 snoImplicitOverride requires the override keyword on any member that redefines a concrete member inherited from a base class, including properties and accessors. It catches renamed or deleted base members, whose overrides would otherwise silently become brand-new members.
solid answer
~50 sWith `noImplicitOverride` on, a derived-class member that redefines a *concrete* member of its base class must be written with the `override` modifier, or the compiler errors. It covers methods, property fields and accessors. It does not apply to implementing an `abstract` member — there is no existing implementation to override — nor to satisfying an `implements` interface, since `override` is about class inheritance only. The bug it catches is the silent decoupling: if someone renames or removes `describe()` on the base class, an unmarked derived `describe()` keeps compiling as a perfectly valid new method that nothing ever calls. Marked with `override`, it becomes a compile error pointing straight at the break. Note the complementary check is always on: writing `override` for a member the base does not declare is an error even with the flag off. And like the rest of the type layer, `override` is erased — the emitted JavaScript is identical.
code
typescript · 11 linesabstract class Repo {
abstract load(id: string): string;
describe(): string { return "repo"; }
}
class UserRepo extends Repo {
load(id: string): string { return id; } // abstract member: no override needed
override describe(): string { return "users"; } // concrete base member: override required
}
console.log(new UserRepo().describe());go deeper
Recall that with this option on you write override on any method that redefines one from the parent class, and that forgetting it is a compile error.
Explain both directions of the check — mandatory annotation plus the always-on error when the base lacks the member — and name the exemptions for abstract members and interface implementations.
Frame it as refactoring insurance on inheritance-heavy code: a base-class rename becomes a compile error in every consumer instead of a silent behaviour change, at zero runtime cost since the modifier is erased.
Decide where inheritance is even the right tool. This flag makes base classes safer to evolve, but if a hierarchy needs it badly, that is evidence to weigh composition or a narrower published surface instead.
## The bug Inheritance in JavaScript is positional by name: a derived class method shadows a base method if and only if the names match. Nothing records the *intent* that the derived member was meant to override something. So consider a base class that renames `describe()` to `summarize()`. Every derived class that defined `describe()` still compiles — the method is now simply a new member of the derived class that no one calls, and the base's implementation silently takes over. The failure is at runtime, far from the rename, and the type-checker had no way to complain because nothing in the code claimed a relationship. `override` is that claim. Once you write it, the compiler enforces both directions. ## The two directions **Always on, regardless of configuration:** if you write `override` on a member the base class does not declare, that is an error — the compiler tells you the member cannot have an `override` modifier because it is not declared in the base class. This is the half that catches renames, and you get it just by adopting the keyword. **Enabled by `noImplicitOverride`:** if a member *does* redefine an inherited concrete member and you did not write `override`, that is an error too. This half exists to make the first half reliable. Without it, `override` is a convention some members follow and others do not, and a rename only breaks the ones that happened to be annotated. With it, the annotation is mandatory, so the guarantee is total. ## Exactly which members The check applies to concrete inherited members of any kind: ```ts class Base { greet(): string { return "b"; } // method name = "b"; // property field get size(): number { return 1; } // accessor } ``` A derived class redefining `greet`, `name` or `size` must mark each with `override`. Two cases are excluded, and knowing them is the discriminator in an interview: - **Implementing an `abstract` member.** An abstract declaration has no implementation to override; the derived class is supplying the first one. No `override` is required. - **Satisfying an `implements` clause.** Interfaces are not inheritance of implementation. `override` describes a relationship to a base *class*, so an interface member never triggers the requirement. ```ts abstract class Repo { abstract load(id: string): string; describe(): string { return "repo"; } } class UserRepo extends Repo { load(id: string): string { return id; } // abstract: no override needed override describe(): string { return "users"; } // concrete base member: required } ``` ## It costs nothing at runtime `override` is a type-layer modifier. It is checked and then erased; the emitted class is byte-for-byte what it would have been without the keyword. That is worth saying out loud in an interview, because it frames the flag correctly: it buys a compile-time guarantee about refactoring safety at zero runtime cost, and enabling it can never change program behaviour. ## Adoption Of the beyond-strict flags, this is usually the cheapest to turn on. The errors are mechanical — the compiler names every member that needs the keyword and the fix is inserting one word — and the count is bounded by how much class inheritance the codebase actually uses. A codebase that favours composition may have almost nothing to change; a framework-heavy codebase with deep base classes has more, but the edit is still rote and safely automatable. The payoff is proportional to inheritance depth and to how many people can change a base class. In a shared library where a base class is public API, `override` turns a whole class of silent breakages into compile errors in every consumer that upgrades — which is exactly the moment you want to hear about them. ## Related but different Do not confuse this with visibility or with method compatibility checking. TypeScript already verifies that an overriding member's type is assignable to the base member's type, with or without this flag. `noImplicitOverride` adds nothing about types; it adds a statement of *intent* that survives future edits to the base class.
- Does implementing an abstract method or an interface member require the `override` keyword under this flag?Neither does. An abstract declaration has no implementation to override — the derived class provides the first one — and an `implements` clause is a structural obligation, not implementation inheritance. `override` describes a relationship to a concrete member of a base class, so only those members trigger the requirement.
- What error do you get if a base class method is renamed while a derived member still carries `override` with the old name?The compiler reports that the member cannot have an `override` modifier because it is not declared in the base class. That check is on regardless of `noImplicitOverride` — the flag's job is to guarantee every overriding member carries the keyword in the first place, so that no rename can slip past unannotated.
- Does adding `override` throughout a codebase change the compiled output in any way?No. It is a type-layer modifier: the compiler checks it and erases it, so the emitted class is identical. That makes the flag risk-free to adopt from a runtime perspective — the only cost is the mechanical edit, and the only effect is that a future base-class rename becomes a compile error instead of a silent behaviour change.
saying these in an interview costs you the question
- Thinks override is required when implementing an interface member
- Believes override affects the emitted JavaScript
- Says override is needed for abstract member implementations
- Assumes the modifier changes which method actually runs
- Confuses it with the compiler's existing signature-compatibility check