Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

Method overriding in TypeScript occurs when a subclass provides a specific implementation for a method that is already defined in its superclass. The subclass method must share the same identifier and possess a type-compatible signature with the base class method. TypeScript 4.3 introduced the explicit override modifier to enforce strict compiler checks during this inheritance mechanism.

Syntax and the override Modifier

The override keyword is placed immediately before the method name in the subclass. It explicitly signals to the compiler that the method is intended to replace a base class implementation. Crucially, the override keyword inherently instructs the compiler to verify that a method with the exact name exists in the base class. If the base method does not exist (e.g., due to a typo or a refactor in the base class), the compiler throws an error regardless of any other compiler configurations.
class Base {
  execute(payload: string): void {}
}

class Derived extends Base {
  override execute(payload: string): void {}
}

class InvalidDerived extends Base {
  // Error: This member cannot have an 'override' modifier because it is not declared in the base class 'Base'.
  override run(payload: string): void {}
}

Compiler Configuration: noImplicitOverride

TypeScript provides the noImplicitOverride compiler option in tsconfig.json. When set to true, the compiler strictly enforces the presence of the override keyword. If a subclass method shares a name with a base class method but lacks the override modifier, the compiler throws an error, preventing accidental shadowing.

Signature Compatibility Rules

TypeScript enforces structural typing rules when a method is overridden. 1. Parameter Bivariance Unlike strict Liskov Substitution Principle (LSP) enforcement which requires contravariance, standard method parameters in TypeScript are bivariant. This remains true even when the strictFunctionTypes compiler option is enabled. Consequently, an overriding method is permitted by the compiler to accept narrower types (subtypes) or wider types (supertypes) than the base class method. It cannot require new mandatory parameters, but it can add new optional parameters.
class Base {
  process(id: number | string): void {}
}

class Derived extends Base {
  // Valid: 'number' is narrower than 'number | string' due to method parameter bivariance
  // Valid: 'metadata' is an added optional parameter
  override process(id: number, metadata?: any): void {}
}
2. Return Type Covariance The overriding method must return the exact same type or a narrower type (a subtype) of the base method’s return type.
class Base {
  fetch(): unknown { return null; }
}

class Derived extends Base {
  // Valid: 'string' is a subtype of 'unknown'
  override fetch(): string { return "data"; }
}
3. Access Modifiers An overriding method can expand the visibility of a base method but cannot restrict it. A protected method can be overridden as public, but a public method cannot be overridden as protected or private.
class Base {
  protected initialize(): void {}
}

class Derived extends Base {
  // Valid: Visibility expanded from protected to public
  public override initialize(): void {}
}

Base Method Invocation

When a method is overridden, the subclass implementation entirely shadows the base class implementation. To execute the original base class logic within the overriding method, the super keyword is used to reference the superclass prototype.
class Base {
  connect(): void {
    // Base connection logic
  }
}

class Derived extends Base {
  override connect(): void {
    super.connect(); // Invokes Base.connect()
    // Subclass-specific connection logic
  }
}
Master TypeScript with Deep Grasping Methodology!Learn More