Reputation: 13
TS accepts a callback function that requires a subclass of the type that it will be called with, but not a completely separate type.
This seems like a bug to me, what gives?
pseudo:
class A ...
class B extends A ...
class C ...
callWithA((a:A)=>void) ...
takeB(b:B) ...
takeC(c:C) ...
callWithA(takeB) // compiles fine, but will break at runtime
callWithA(takeC) // does not compile
Full example:
class A {
a: string;
}
class B extends A {
b: string;
}
class C {
c: string;
}
function callWithA(callbackfn: (value: A) => void): void {
callbackfn(new A());
}
function callWithB(callbackfn: (value: B) => void): void {
callbackfn(new B());
}
function takeA(a: A) {
console.log('takeA got', a);
console.log('#');
}
function takeB(b: B) {
console.log('takeB got', b);
console.log('#');
}
function takeC(c: C) {
console.log('takeC got', c);
console.log('#');
}
function takeString(s: String) {
console.log('takeString got', s);
console.log('#');
}
let a: A
a = new B();
let b: B;
// b = new A(); // incompatible, Good!
// takeB(new A()); // incompatible, Good!
callWithA(takeA); // takeA(a:A) will be called with an A, OK
callWithA(takeB); // BUG HERE ?! takeB(b:B) will be called with an A!! not good!
// callWithA(takeC); // incompatible, good, A is not a C
// callWithA(takeString); // incompatible, good
callWithB(takeA); // takeA(a:A) will be called with a B, OK
callWithB(takeB); // takeB(b:B) will be called with a B, OK
// callWithB(takeC); // incompatible, good, A is not a C
// callWithB(takeString); // incompatible, good
I would expect the compiler to refuse to use the incompatible callback 'takeB'
I have seen that TS does accept calling functions with subclass of the required arguments, which can cause problems:
addDog(arr: Animal[]) {arr.append(new Dog())}
let cats: Cat[] = []
addDog(cats) // Works, since cats are animals, but then we get dogs in a array of cats
But this seems different, and calling the callback directly does not compile.
Is this a bug, or 'By Design'.?
Upvotes: 1
Views: 63
Reputation: 250016
By default function parameters are bivariantly. There is a compiler flag that will make this an error and it's called strictFunctionTypes
. With this flag the call you highlight will be an error.
You can read more about it here
Upvotes: 1