How to enforce the Liskov substitution principle in Typescript

70 Views Asked by At

The compare (overridden) methods have different signatures than their super's compare:

abstract class Person {
  public abstract compare(that: Person): boolean;
}

class Student extends Person {
  constructor(private readonly maxGrade: number) { super(); }
  public override compare(that: Student) {
    return this.maxGrade > that.maxGrade;
  }
}

class Lawyer extends Person {
  constructor(private readonly yearlyIncome: number){ super(); }
  public override compare(that: Lawyer) {
    return this.yearlyIncome < that.yearlyIncome;
  }
}

// const s = new Student(96);
// const soul = new Lawyer(7400);
// console.log(s.compare(soul));
  • This seems to violate the Liskov Substitution Principle, but Typescript gives no error.
  • Equivalent python code (below) gives an error.
  • Only when I uncomment an actual comparison between a Student and a Lawyer, I get the desired error.
  • Here is the python code + error message for completeness:
from __future__ import annotations
from abc import ABC
from abc import abstractmethod

import dataclasses

class Person(ABC):

    @abstractmethod
    def equals(self, other: Person) -> bool:
        ...

@dataclasses.dataclass
class Student(Person):
    max_grade: int

    # $ mypy main.py
    # main.py:22: error: Argument 1 of "equals" is incompatible with supertype "Person"; supertype defines the argument type as "Person"  [override]
    # main.py:22: note: This violates the Liskov substitution principle
    # main.py:22: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
    # Found 1 error in 1 file (checked 1 source file)
    def equals(self, other: Student) -> bool:
        return self.max_grade > other.max_grade

    # this works fine
    #def equals(self, other: Person) -> bool:
    #    if isinstance(other, Student):
    #        return self.max_grade > other.max_grade
    #    return False
0

There are 0 best solutions below