user1803245
user1803245

Reputation: 13

TS callback function parameters seem to be incompletely checked

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

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

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

Related Questions