How to fix The return type does not match the base signature in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025ยท 120 views

This TypeScript error occurs when a method override or implementation has a return type that doesn't match the parent class or interface definition. It ensures type safety when extending classes or implementing interfaces by enforcing consistent return types across the inheritance hierarchy. Understanding method signature compatibility and proper type annotations resolves this object-oriented programming error.

Quick fix

Fixes TS2416

// Base class with method signature
class Animal {
  makeSound(): string {
    return "generic animal sound";
  }
}

// Subclass with incompatible override
class Dog extends Animal {
  // ERROR: The return type does not match the base signature
  makeSound(): number {
    return 42; // returning number instead of string
  }
}
  1. Identify the base method signature and your override
  2. Ensure return type is assignable to the base return type
  3. Handle async methods and Promises correctly
  4. Use covariant return types when appropriate
typescript โ€” error
// Base class with method signature
class Animal {
makeSound(): string {
return "generic animal sound";
}
}
// Subclass with incompatible override
class Dog extends Animal {
// ERROR: The return type does not match the base signature
makeSound(): number {
return 42; // returning number instead of string
}
}
The return type does not match the base signature

What this error means

This TypeScript error occurs when you override a method in a subclass or implement an interface method with an incompatible return type. TypeScript enforces strict type checking for method overrides to ensure that subclasses maintain the contract defined by their parent class or interface. The "base signature" refers to the method declaration in the parent class or interface, and your override must have a return type that is assignable to (compatible with) that base return type. This is part of TypeScript's type safety system for object-oriented programming, preventing subtle bugs where a subclass method might return a different type than what callers of the parent class method expect. The error ensures that polymorphism works correctly: code that works with a parent class reference can safely call methods and expect consistent return types, even when the actual object is an instance of a subclass.

Typical symptoms

  • TypeScript compiler shows error "TS2416: Property 'methodName' in type 'ClassName' is not assignable to the same property in base type 'BaseClassName'"
  • The error message specifically mentions "The return type does not match the base signature"
  • Method overrides in subclasses are highlighted with errors in your IDE
  • Interface implementations show type mismatches for method return types
  • Build process fails when running `npm run build` or `tsc`
  • The error points to a specific method declaration with line numbers
  • Error appears when extending classes or implementing interfaces with method overrides

Common causes

  1. Overriding a method with a completely different return type (string instead of number, etc.)
  2. Returning a more specific type that isn't assignable to the base return type
  3. Using a union type in the override that isn't compatible with the base return type
  4. Missing return type annotation causing TypeScript to infer an incompatible type
  5. Generic type parameters in the override don't match the base method's generics
  6. Returning a subtype that doesn't satisfy the Liskov Substitution Principle
  7. Async method overrides where the Promise generic type doesn't match
  8. Overriding a method that returns void with a method that returns a value (or vice versa)
  9. Covariant return types not properly handled (returning a more specific type is usually allowed, but TypeScript has strict rules)

How to fix "The return type does not match the base signature"

1Identify the base method signature and your override

First, locate both the base method (in parent class or interface) and your overriding method. Compare their return types carefully. The error message will show both types.

typescript
// Base class with method signature
class Animal {
  makeSound(): string {
    return "generic animal sound";
  }
}

// Subclass with incompatible override
class Dog extends Animal {
  // ERROR: The return type does not match the base signature
  makeSound(): number {
    return 42; // returning number instead of string
  }
}
2Ensure return type is assignable to the base return type

The overriding method's return type must be assignable to (compatible with) the base return type. For objects, this usually means the return type must have all the properties of the base type (structural typing). For primitives, the types must match exactly or be compatible through type relationships.

typescript
// Base interface
interface Shape {
  getArea(): number;
}

// Correct implementation - same return type
class Circle implements Shape {
  getArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}

// Also correct - returning a subtype (number literal type)
class Square implements Shape {
  getArea(): 100 {  // 100 is assignable to number
    return 100;
  }
}

// ERROR - string not assignable to number
class Triangle implements Shape {
  getArea(): string {
    return "100";
  }
}
3Handle async methods and Promises correctly

When overriding async methods or methods returning Promises, ensure the Promise generic type matches. An async method that returns Promise<string> cannot be overridden with a method returning Promise<number>.

typescript
abstract class DataFetcher {
  abstract fetchData(): Promise<string>;
}

// Correct - same Promise type
class ApiFetcher extends DataFetcher {
  async fetchData(): Promise<string> {
    const response = await fetch("/api/data");
    return response.text();
  }
}

// ERROR - Promise<number> not assignable to Promise<string>
class NumberFetcher extends DataFetcher {
  async fetchData(): Promise<number> {
    return 42;
  }
}

// Also correct - returning a subtype
class JsonFetcher extends DataFetcher {
  async fetchData(): Promise<string> {
    const response = await fetch("/api/json");
    const data = await response.json();
    return JSON.stringify(data); // returns string
  }
}
4Use covariant return types when appropriate

TypeScript allows covariant return types in method overrides - you can return a more specific (subtype) of the base return type. This is often useful and type-safe.

typescript
class Vehicle {
  getEngine(): Engine {
    return new Engine();
  }
}

class Car extends Vehicle {
  // CORRECT - TurboEngine extends Engine, so this is covariant
  getEngine(): TurboEngine {
    return new TurboEngine();
  }
}

class Engine {}
class TurboEngine extends Engine {}

// This works because TurboEngine can be used wherever Engine is expected
const car = new Car();
const engine: Engine = car.getEngine(); // TurboEngine is assignable to Engine
5Check generic type parameters in method signatures

If the base method uses generic type parameters, your override must handle them correctly. You can use the same generics or provide specific types that satisfy the constraints.

typescript
interface Repository<T> {
  findById(id: string): T | null;
}

// Correct - same generic type
class UserRepository implements Repository<User> {
  findById(id: string): User | null {
    // implementation
    return null;
  }
}

// ERROR - return type doesn't match
class ProductRepository implements Repository<Product> {
  findById(id: string): string | null {  // string not assignable to Product
    return "product data";
  }
}

// For generic methods within classes
class Base {
  process<T>(value: T): T {
    return value;
  }
}

class Derived extends Base {
  // Can override with same signature
  process<T>(value: T): T {
    return super.process(value);
  }
  
  // ERROR - different return type
  process<T>(value: T): string {
    return "converted";
  }
}
6Handle void return types correctly

Methods returning void in the base class can be overridden with methods that return any type (the return value is ignored). However, methods with non-void return types cannot be overridden with void methods.

typescript
class EventEmitter {
  // Base method returns void
  onEvent(): void {
    console.log("event");
  }
}

class MyEmitter extends EventEmitter {
  // CORRECT - can return a value even though base returns void
  onEvent(): string {
    console.log("my event");
    return "handled";  // This is allowed!
  }
}

class Reader {
  // Base method returns string
  read(): string {
    return "data";
  }
}

class MyReader extends Reader {
  // ERROR - void not assignable to string
  read(): void {
    console.log("reading");
  }
}
7Use explicit return type annotations

When overriding methods, explicitly annotate the return type rather than relying on TypeScript inference. This makes your intent clear and helps catch errors early.

typescript
interface Calculator {
  calculate(x: number, y: number): number;
}

// Without explicit annotation, TypeScript might infer wrong type
class BadCalculator implements Calculator {
  calculate(x: number, y: number) {
    // TypeScript infers return type as string here
    return (x + y).toString(); // ERROR: string not assignable to number
  }
}

// With explicit annotation, error is clearer
class GoodCalculator implements Calculator {
  calculate(x: number, y: number): number {  // Explicit return type
    return x + y;  // Correct
  }
}
8Review method overloads and union types

If the base method has overloads or returns a union type, ensure your override satisfies all possible cases. The override must be assignable to all base signatures.

typescript
// Base with overloads
class Parser {
  parse(input: string): string;
  parse(input: number): number;
  parse(input: string | number): string | number {
    return input;
  }
}

// Override must handle all cases
class MyParser extends Parser {
  // ERROR - doesn't match all overloads
  parse(input: string): string {
    return input.toUpperCase();
  }
}

// Correct - matches all overloads
class CorrectParser extends Parser {
  parse(input: string): string;
  parse(input: number): number;
  parse(input: string | number): string | number {
    if (typeof input === "string") {
      return input.toUpperCase();
    } else {
      return input * 2;
    }
  }
}

Advanced notes

TypeScript's method override checking follows the Liskov Substitution Principle (LSP), which states that objects of a superclass should be replaceable with objects of its subclasses without breaking the program. For return types, this means covariant return types are allowed (returning a subtype) because a more specific type can be used wherever a more general type is expected. However, TypeScript is stricter than some other languages: it requires explicit compatibility. The strictFunctionTypes compiler option affects method parameter checking (contravariance) but not return type checking. When working with abstract classes and interfaces, remember that all abstract methods must be implemented with compatible return types. For generic classes and methods, type parameter constraints must be satisfied. The override keyword (available in TypeScript 4.3+) can help catch errors by requiring explicit annotation of method overrides. When dealing with complex inheritance hierarchies, consider using composition over inheritance or defining more flexible type signatures with union types or generic constraints.

Frequently asked questions

What does "TS2416" mean?
This TypeScript error occurs when you override a method in a subclass or implement an interface method with an incompatible return type. TypeScript enforces strict type checking for method overrides to ensure that subclasses maintain the contract defined by their parent class or interface. The "base signature" refers to the method declaration in the parent class or interface, and your override must have a return type that is assignable to (compatible with) that base return type.
How do I fix "TS2416"?
This TypeScript error occurs when a method override or implementation has a return type that doesn't match the parent class or interface definition. It ensures type safety when extending classes or implementing interfaces by enforcing consistent return types across the inheritance hierarchy. Understanding method signature compatibility and proper type annotations resolves this object-oriented programming error.
What causes "TS2416"?
Overriding a method with a completely different return type (string instead of number, etc.) Returning a more specific type that isn't assignable to the base return type Using a union type in the override that isn't compatible with the base return type
Is the "TS2416" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading