This error means a class that inherits from another class (a "derived class") failed to call the parent class’s constructor using super().

Here’s what’s actually broken: the derived class’s constructor is trying to access this before the parent class’s initialization is complete, which is a fundamental rule of JavaScript/TypeScript class inheritance. The super() call is what ensures the parent class’s setup happens first, making this a valid, initialized object for the derived class to work with.

Common Causes and Fixes

  1. Missing super() Call Entirely:

    • Diagnosis: Look for a derived class constructor that doesn’t have a super() call as its first statement.
    • Fix: Add super() as the very first line in the derived class’s constructor.
      class Parent {
          constructor(public name: string) {}
      }
      
      class Child extends Parent {
          constructor(public age: number) {
              // Missing super() here
              this.age = age; // Error occurs here
          }
      }
      
      Fixed:
      class Parent {
          constructor(public name: string) {}
      }
      
      class Child extends Parent {
          constructor(public age: number) {
              super("defaultName"); // Call parent constructor
              this.age = age;
          }
      }
      
    • Why it works: super() invokes the parent class’s constructor, setting up the inherited properties and methods before the child class can add its own.
  2. super() Called After Other this References:

    • Diagnosis: The super() call exists but is not the first statement in the constructor. Any use of this before super() will trigger the error.
    • Fix: Move the super() call to be the absolute first statement.
      class Parent {
          constructor(public id: number) {}
      }
      
      class Child extends Parent {
          constructor(public id: number, public label: string) {
              console.log(this.id); // Error: 'this' is used before super()
              super(id);
          }
      }
      
      Fixed:
      class Parent {
          constructor(public id: number) {}
      }
      
      class Child extends Parent {
          constructor(public id: number, public label: string) {
              super(id); // Call parent constructor first
              console.log(this.id); // Now this.id is valid
              this.label = label;
          }
      }
      
    • Why it works: JavaScript enforces that this is not accessible until the parent constructor has completed its initialization via super().
  3. Derived Class Has No Constructor (But Parent Does):

    • Diagnosis: If a derived class doesn’t define its own constructor, TypeScript implicitly provides one. If the parent class has a constructor that requires arguments, and the derived class doesn’t define its own constructor to pass those arguments up, you’ll get this error.
    • Fix: Define a constructor in the derived class that calls super() with the necessary arguments.
      class Vehicle {
          constructor(public wheels: number) {}
      }
      
      class Car extends Vehicle {} // No constructor here
      // If Vehicle's constructor required an argument, this would error.
      // For example, if Vehicle had constructor(public brand: string, public wheels: number) {}
      // and you tried to create `new Car()`, it would fail because `wheels` is missing.
      // The TS2377 error is more subtle: it happens when the *parent* requires *arguments*
      // and the child *omits* its constructor, meaning the parent's constructor isn't called.
      
      Example leading to TS2377:
      class ParentWithArgs {
          constructor(public value: string) {}
      }
      class ChildNoConstructor extends ParentWithArgs {
          // No constructor defined here
      }
      // const instance = new ChildNoConstructor(); // This would cause TS2377 if ParentWithArgs required args.
      // The *actual* TS2377 error arises when the derived class *has* a constructor, but doesn't call super.
      // Let's illustrate the *common* scenario leading to TS2377, which is a derived class *with* a constructor.
      class Base {
          constructor(public message: string) {}
      }
      class Derived extends Base {
          constructor(public data: number) {
              // If Base required arguments and this Derived class constructor
              // doesn't call super() with them, TS2377 occurs.
              // The most direct TS2377 is when super() is missing entirely or misplaced.
              // Let's focus on the direct error:
              // this.data = data; // Error: This is where the error is caught, but the root is missing super()
          }
      }
      
      Fixed:
      class Base {
          constructor(public message: string) {}
      }
      class Derived extends Base {
          constructor(public message: string, public data: number) {
              super(message); // Pass arguments to parent constructor
              this.data = data;
          }
      }
      
    • Why it works: By defining a constructor in the derived class and explicitly calling super() with the arguments expected by the parent’s constructor, you ensure the parent is properly initialized.
  4. super() Called Conditionally:

    • Diagnosis: super() is inside an if statement or is otherwise not guaranteed to be called on every code path through the constructor.
    • Fix: Ensure super() is called unconditionally at the beginning of the constructor.
      class Configurable {
          constructor(public setting: string | undefined) {}
      }
      
      class Widget extends Configurable {
          constructor(public name: string, setting?: string) {
              if (setting) {
                  super(setting); // super() is conditional
              }
              this.name = name;
          }
      }
      
      Fixed:
      class Configurable {
          constructor(public setting: string | undefined) {}
      }
      
      class Widget extends Configurable {
          constructor(public name: string, setting?: string) {
              super(setting); // Call super unconditionally
              this.name = name;
          }
      }
      
    • Why it works: The super() call must execute for every instance of the derived class to correctly set up its inherited state.
  5. Abstract Base Class Constructor Not Called (Less Common but Possible):

    • Diagnosis: If your base class is abstract and has a constructor, a concrete derived class must still call super(). The abstract keyword doesn’t exempt derived classes from constructor initialization rules.
    • Fix: Add super() to the derived class’s constructor.
      abstract class AbstractBase {
          constructor(public id: string) {
              console.log("AbstractBase initialized with", id);
          }
      }
      
      class ConcreteChild extends AbstractBase {
          constructor(public id: string, public value: number) {
              // Missing super()
              this.value = value; // Error here
          }
      }
      
      Fixed:
      abstract class AbstractBase {
          constructor(public id: string) {
              console.log("AbstractBase initialized with", id);
          }
      }
      
      class ConcreteChild extends AbstractBase {
          constructor(public id: string, public value: number) {
              super(id); // Call parent constructor
              this.value = value;
          }
      }
      
    • Why it works: Even though the abstract class cannot be instantiated directly, its constructor’s logic (if any) must run to initialize inherited properties for any concrete subclass.
  6. Inheriting from a Class with a Constructor that Throws:

    • Diagnosis: If the parent class’s constructor throws an error, and the derived class’s constructor doesn’t handle it or is structured such that super() is called after a point where the error might occur, you might see this. However, TS2377 specifically relates to the structure of the derived constructor, not necessarily the parent’s runtime behavior. The most direct cause is still structural.
    • Fix: Ensure super() is the first statement. If the parent constructor itself has a bug that causes it to throw, that’s a separate issue to debug in the parent class.
      class FaultyParent {
          constructor() {
              if (true) { // Example of a condition that might lead to an error
                  throw new Error("Parent initialization failed!");
              }
          }
      }
      
      class ChildOfFaulty extends FaultyParent {
          constructor() {
              // If FaultyParent's constructor throws, this error might manifest
              // as TS2377 if the derived constructor isn't structured correctly,
              // but more likely, you'd just see the thrown error from FaultyParent.
              // The TS2377 specifically points to the derived class's failure to call super.
              super(); // This line is essential for TS2377
              // If super() itself throws, the error is from the parent.
              // If super() is *missing*, TS2377 is the compile-time error.
          }
      }
      
      Fix: The fix remains the same: ensure super() is the first statement. The underlying issue of the parent throwing must be addressed separately.
    • Why it works: super() is the gateway. If it’s correctly placed, the derived class acknowledges its dependency on the parent’s initialization.

The next error you might encounter after fixing this is related to how you’re passing arguments to super(), or if the parent class’s constructor has other unmet preconditions.

Want structured learning?

Take the full Typescript course →