Derived Constructor Without super()
ID |
javascript.constructor_super |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
reliability, suspicious-control-flow |
Description
Reports an explicit constructor in a class that uses extends but never calls super(…) in its body. ECMAScript requires every derived-class constructor to invoke the super-class constructor before referencing this or returning normally; if it does not, the JavaScript engine throws ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
This is a v1 implementation: a single visible super(…) call anywhere in the body — even inside a conditional — is enough to satisfy the rule. Calls inside nested function or class bodies do not count, because they belong to a different function scope.
The inverse case (a non-derived constructor that calls super()) is intentionally out of scope here; it is covered by a separate rule.
Rationale
-
Forgetting
super()in a derived class is a hard runtime error, not a stylistic issue. The error is masked when the failing path is rarely exercised in tests. -
Implicit constructors (no
constructor() { … }declared) are safe — the engine generatesconstructor(…args) { super(…args); }for you. -
A
super()placed inside an inner closure is not a real super-call from the constructor’s point of view; readers may be misled into thinking the rule is satisfied.
// Bad
class Greeter extends Base {
constructor(name) {
this.name = name; // ReferenceError before super() runs
}
}
// Bad: super() inside an inner function does not count
class Wrapper extends Base {
constructor() {
const init = () => { super(); };
init(); // syntax error in real JS, and even if it parsed,
// the call would not satisfy the constructor itself
}
}
Remediation
Call super(…) from the constructor body — either unconditionally at the top, or in every reachable branch.
// Good
class Greeter extends Base {
constructor(name) {
super();
this.name = name;
}
}
If the derived class does not need any constructor logic of its own, drop the explicit constructor entirely and rely on the implicit constructor(…args) { super(…args); }.