
extends and super in JavaScript Classes

Learning JavaScript classes is one thing. Learning what happens when one class extends another is where developers usually start tripping over the edges.
The syntax looks friendly enough:
class AdminUser extends User {}But once constructors, overridden methods, and super calls enter the picture, it becomes clear that class inheritance is not just about nicer‑looking syntax. There are a few important rules involved, and the language is quite strict about some of them.
The good news is that the mental model is manageable if you separate the moving parts.
extends creates a subclass relationship
At a basic level:
class User { constructor(public name: string) {}}class AdminUser extends User {}AdminUser is now a subclass of User.
That means instances of AdminUser inherit methods from User, and the subclass can add or override behaviour of its own.
The Subclass Gets the Parent Methods
If the parent class defines a method, the child class can use it:
class User { constructor(public name: string) {} getGreeting(): string { return `Hello, ${this.name}`; }}class AdminUser extends User {}const admin = new AdminUser('Ellie');console.log(admin.getGreeting());That works even though AdminUser did not define getGreeting() itself.
super() matters in subclass constructors
This is the rule that catches almost everyone at some point.
If a subclass defines its own constructor, it must call super() before using this:
class User { constructor(public name: string) {}}class AdminUser extends User { constructor(name: string, public permissions: string[]) { super(name); }}super(name) calls the parent class constructor.
Without that, JavaScript does not let the subclass initialise itself properly.
Why super() has to come first
If you try to use this before calling super() in a subclass constructor, JavaScript throws an error.
That is because the parent part of the instance has not been initialised yet.
Seen practically, the rule is:
- the parent constructor sets up the base object
- the child constructor then adds or customises subclass‑specific state
It is one of those places where the language is being stricter than people first expect, but the rule is sensible once you see what problem it is preventing.
Subclasses Can Override Methods
This is where inheritance starts to feel more expressive:
class User { constructor(public name: string) {} getRoleLabel(): string { return 'User'; }}class AdminUser extends User { getRoleLabel(): string { return 'Administrator'; }}Now the child class replaces the inherited version with its own implementation.
That can be useful when subclasses need slightly different behaviour while still sharing a common base structure.
super.methodName() lets us build on parent behaviour
Overriding does not mean discarding the parent method completely.
Sometimes we want to reuse it and extend it:
class User { getGreeting(): string { return 'Welcome back'; }}class AdminUser extends User { getGreeting(): string { return `${super.getGreeting()}, administrator`; }}Here, super.getGreeting() calls the parent method, and the subclass layers something extra on top.
That is often cleaner than duplicating the whole parent implementation.
Inheritance is Useful, but It is Easy to Overdo
This is the practical warning worth carrying alongside the syntax.
Small class hierarchies can be neat:
- a base UI component
- a specialised subclass
- shared behaviour in one place
But deep inheritance trees often become awkward. A change in the parent can ripple through several layers, and it becomes harder to understand where behaviour is really coming from.
That is why developers often say "prefer composition over inheritance" in modern JavaScript applications.
They are not saying inheritance is bad. They are saying it should be used where the relationship is genuinely clear and stable.
extends is not only for your own classes
JavaScript also allows subclassing built‑in types in modern class syntax, though this is a corner you should enter carefully.
The wider point is that extends is the formal class‑inheritance mechanism in ES6. It gives JavaScript a clearer surface for something the language already had through prototypes, but it does not remove the need for design judgement.
A Realistic Example
Suppose we are modelling notifications:
class Notification { constructor(public message: string) {} format(): string { return this.message; }}class ErrorNotification extends Notification { format(): string { return `Error: ${super.format()}`; }}That is a fairly sensible inheritance relationship. The child is a more specific version of the parent, and the shared behaviour is genuinely shared.
That kind of use is usually where classes feel most natural.
The Important Rules are Simpler than They First Appear
If you strip away the jargon, the main ideas are:
extendsmeans one class builds on another- subclasses inherit parent methods
- subclass constructors must call
super()before usingthis - overriding lets a child replace inherited behaviour
super.method()lets a child reuse parent behaviour while extending it
That is enough to reason about most code using ES6 class inheritance.
Syntax is Only Half the Story
The existence of extends and super does not mean every shared behaviour should become a class hierarchy. The harder question is usually architectural:
- is this truly an "is‑a" relationship
- does the subclass genuinely specialise the parent
- will the hierarchy stay understandable as the application grows
When the answer is yes, extends and super give you a readable way to express it.
When the answer is no, inheritance usually starts to feel clever before it starts to feel helpful.
That is the right note to end on. These features are useful, but they work best when they are serving a clear design rather than trying to create one by themselves.
Related Articles

JavaScript Essentials for Freelance Web Developers. 
React's Reconciliation Algorithm Explained. React's Reconciliation Algorithm Explained

Implementing Server‑Side Rendering (SSR) in Vue. Implementing Server‑Side Rendering (SSR) in Vue

React's Virtual DOM vs. the Real DOM. React's Virtual DOM vs. the Real DOM
Handling Click Events in JavaScript. Handling Click Events in JavaScript

Understanding prototype.apply() in JavaScript. Understanding
prototype.apply()in JavaScript
Understanding Transient Props in styled‑components. Understanding Transient Props in
styled‑components
Rethinking Carousels: Going Around in Circles. Rethinking Carousels: Going Around in Circles

What GEO is, and Why It is Not Just SEO for AI. What GEO is, and Why It is Not Just SEO for AI

Hiring a Freelance Front‑End Developer ‑ An Ultimate Guide. Hiring a Freelance Front‑End Developer ‑ An Ultimate Guide

Manipulate Elements with CSS transform. Manipulate Elements with CSS
transform
The Execution Context in JavaScript. The Execution Context in JavaScript