Reputation: 913
In TypeScript you are allowed to have a covariant method parameter in the derived class.
It looks like a blatant violation of LSP.
What is an intention for this piece of the language design, is it deliberate or a design limitation?
interface A {
a: number;
}
interface B extends A {
b: number;
}
class Base {
public foo(arg0: A): B {
return { a: 0, b: 42 };
}
}
class Derived extends Base {
public foo(arg0: B): B { // covariant parameter is allowed, not OK
return { a: +arg0.a.toPrecision(2), b: +arg0.b.toPrecision(2) }; // runtime error, b is undefined, although should have been required
}
}
let b: Base = new Derived(); // Assign a sub class to a base class should always be ok
b.foo({ a: 10}); // no need to pass in b, right ?
Upvotes: 5
Views: 966
Reputation: 249466
Methods parameters behave bivariantly in typescript. There is a proposal to make them behave contravariantly, but since it's been open since 2016, it probably isn't a priority.
There is an option (strictFunctionTypes
) to make parameters of function signatures not originating in methods behave contravariantly but methods are explicitly exempt from the stricter checks. From the PR introducing this stricter mode for functions we get an idea of the reasoning behind the method exemption:
Methods are excluded specifically to ensure generic classes and interfaces (such as Array) continue to mostly relate covariantly. The impact of strictly checking methods would be a much bigger breaking change as a large number of generic types would become invariant (even so, we may continue to explore this stricter mode).
Upvotes: 4