Tobias Sjondin Tobias Sjondin -3 years ago 67
TypeScript Question

Typechecking of array of class in function interface

In TypeScript, when creating a function interface and using that as the type expected by another function (i.e. a function expecting a callback), and the parameter of the callback function is an array of a class. The typechecking does not seem to be able to handle it:

"use strict";

class A {
/* no-op */
}

interface C {
(s: Array<A>): void
}

const B = (c: C) => {
c(["Hello World!"]);
};

B((s: Array<A>) => {console.log("Should work", s)});
B((s: A) => {console.log("Should not work", s)});


In this case I believe the second call to B should fail typechecking, as it does when not expecting an array of class instances, but instead a primitive such as string:

"use strict";

interface C {
(s: Array<string>): void
}

const B = (c: C) => {
c(["Hello World!"]);
};

B((s: Array<string>) => {console.log("Should work", s)});
B((s: string) => {console.log("Should not work", s)});


Which fails typechecking with:

test.ts(12,3): error TS2345: Argument of type '(s: string) => void' is not assignable to parameter of type 'C'.
Types of parameters 's' and 's' are incompatible.
Type 'string[]' is not assignable to type 'string'.


I could not find anything regarding this when attempting to search for answers and I'm using TypeScript 2.3.4.

Answer Source

The reason you're not getting any compilation errors is that your A class is empty and since typescript is based on structural subtyping the empty class/object matches everything, for example:

class A {}

let a1: A = 4;
let a2: A = true;
let a3: A = "string";

All fine, with no compilation errors.

When you introduce a member into class A then you start getting errors:

class A {
    dummy: number;
}

let a1: A = 4; // ERROR: Type '4' is not assignable to type 'A'
let a2: A = true; // ERROR: Type 'true' is not assignable to type 'A'
let a3: A = "string"; // ERROR: Type '"string"' is not assignable to type 'A'

const B = (c: C) => {
    c(["Hello World!"]); // ERROR: Argument of type 'string[]' is not assignable to parameter of type 'A[]'
};

B((s: A) => { console.log("Should not work", s); }); // ERROR: Argument of type '(s: A) => void' is not assignable to parameter of type 'C'
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download