Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript: Convert interface to class

Tags:

typescript

I have the following code:

interface X {
    type : string;
    val : number;
}

class X1 implements X {
    type : string;
    val : number;
}

var p1 : X[] = [{type:'a', val:8}];

for (var n in p1) {
    var p2 : X1 = p1[n];
}
var p3 : X1 = p1[0];

Both p2 and p3 are declared as having type X1 and are initialized with a value of type X.

The compiler happily accepts the declaration of p2, but it complains about p3 saying "Cannot convert 'X' to 'X1'".

Why this difference?

like image 463
oz1cz Avatar asked Feb 20 '13 12:02

oz1cz


1 Answers

Everything that implements X should be convertible to X, but not necessarily convertible to X1.

Here is more detail. The code below shows a simple example. Essentially, if you have something of type X (interface) it could be implemented by either X1 (class) or X2 (class).

While you can downgrade a type (from the implementation down to the interface) you can't upgrade a type (from the interface to a specific implementation) because you can't guarantee that what you have is compatible.

Another way of looking at this is that you can make something less specific than it is, but you can't make something more specific than it is.

interface X {
    type : string;
    val : number;
}

class X1 implements X {
    type : string;
    val : number;
}

class X2 implements X {
    type: string;
    val: number;
    myMethod() {

    }
}

var x1 = new X1();
var x2 = new X2();

var exampleA: X = x1; // happy
var exampleB: X = x2; // happy

var exampleC: X1 = exampleA; // Not happy...

The upshot of all of this is that you need to cast it:

var exampleC: X1 = <X1>exampleA; // happy...

But be cautious, because you could do this, which wouldn't actually work:

var exampleC: X2 = <X2>exampleA; // seems happy...
exampleC.myMethod(); // oh dear!

Update

In respect of this piece of code...

for (var n in p1) {
    var p2 : X1 = p1[n];
}

In JavaScript this isn't equivalent to a foreach loop. What this is normally used for is iterating over properties in an object and when you use it on an array it will only show explicitly set indexes (not all items). To iterate over an array, you should be using:

for (var i = 0; i < p1.length; i++) {
    var p2 : X1 = p1[i]; // same warning as before
}

So how come TypeScript allows p1[n] to be allocated to an X1 variable? Interesting question and the answer lies here...

If you hover over p1[n] you'll see a type of X[] - this is the type of p1, not the type of p1[n]. If you check this example, you'll find that p1[n] is of type any:

var example = p1['test']; // I used 'test' because n is a string.

Because it is of type any the compiler allows you to tell it to treat it as an X1. So you are converting from any to X1 not from X to X1 as you might have thought.

like image 53
Fenton Avatar answered Sep 25 '22 02:09

Fenton