6

我有以下代码:

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];

p2 和 p3 都被声明为 X1 类型,并使用 X 类型的值进行初始化。

编译器很高兴地接受了 p2 的声明,但它抱怨 p3 说“无法将 'X' 转换为 'X1'”。

为什么会有这种差异?

4

1 回答 1

14

实现的所有东西都X应该可以转换为X,但不一定可以转换为X1

这里有更多细节。下面的代码显示了一个简单的示例。本质上,如果你有某种类型X(接口),它可以由X1(类)或X2(类)实现。

虽然您可以降级一个类型(从实现降级到接口),但您不能升级一个类型(从接口到特定实现),因为您不能保证您所拥有的是兼容的。

另一种看待这个问题的方法是,你可以做一些比它具体的东西,但你不能做一些比它具体的东西。

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...

所有这一切的结果是你需要强制转换它:

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

但要小心,因为你可以这样做,这实际上是行不通的:

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

更新

关于这段代码...

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

在 JavaScript 中,这不等同于foreach循环。这通常用于迭代对象中的属性,当您在数组上使用它时,它只会显示显式设置的索引(不是所有项目)。要遍历数组,您应该使用:

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

那么 TypeScript 是如何允许p1[n]分配给X1变量的呢?有趣的问题和答案就在这里...

如果您将鼠标悬停在上方,p1[n]您会看到一个类型X[]- 这是 的类型p1,而不是 的类型p1[n]。如果你检查这个例子,你会发现它p1[n]的类型是any

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

因为它是类型any,所以编译器允许你告诉它把它当作一个X1. 因此,您正在从转换anyX1X转换X1为您可能认为的转换。

于 2013-02-20T13:25:37.373 回答