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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With