Search code examples
typescriptoverloadingliskov-substitution-principle

How to require Liskov-compliant overloads in TypeScript?


With the following setup:

class Base {
    doSomething(value: unknown): void {}
}

class Child extends Base {
    override doSomething(): void {}
}

… I expected a compiler error, related to the value: unknown parameter missing in Child's overload of doSomething due to the violation of LSP, but there is no such error (as seen in the playground).

Is there a way to enforce Child.doSomething() to extend upon Base.doSomething(), rather than overriding it completely?


Solution

  • A bit simplified example:

    
    let base = (value: unknown) => { }
    
    let child = () => { }
    
    base = child
    
    base(42) // ok
    

    Assign of child to base is safe. Calling base with argument base(42) should not provide any unsafe behavior or error because it actually calls child which does not expect any argument.

    From the other hand, assigning child to base is unsafe:

    let base = (value: unknown) => {
        console.log(value)
    }
    
    let child = () => { }
    
    child = base // error
    
    child()
    

    TS forbids you to assign base to child because base expects some argument and calling child without argument might cause a runtime error.

    More about function assignability you can find in the docs