如何在接口之间进行转换

时间:2015-07-27 08:04:43

标签: typescript

我很惊讶我无法在接口之间进行转换。

interface IA {
    a:string;
}

interface IB {
    b:string;   
}

class example implements IA, IB {
    public a:string;
    public b:string;
}

var a : IA = new example();

// nope - "Neither IA nor IB are assignable to each other"
var b : IB = <IB>(a);

这样做的预期方式是什么?通过任何?

投射
// ok
var c : IB = <IB><any>(a);

1 个答案:

答案 0 :(得分:2)

如果你有example,它会很乐意接受IAIB的类型断言,因为它与这两种类型兼容。

IAIB不兼容,因此如果您尝试使用类型断言,编译器会发出警告。

您可以使用以下方法执行类型安全扩展:

var c : IB = <example> a;

或者,如果您需要兼顾完全不兼容的类型,则必须首先扩展到any

var c: IB = <IB><any>(crazy);

我首选的代码实际上是改变这一行 - 在这种情况下你不需要那么多地处理事情(即让编译器知道你有一个example的实例:

var a = new example();
  

转换的目的是告诉编译器您要将实例用作它无法推断的类型。防止接口之间的转换似乎不一致,没有用,并且不能防止任何错误。我无法理解为什么它不遵循C#并且表现得像向下铸造类。

检查上面提供的示例,因此是类型安全的。

// Allowed
var c : IB = <example> a;

// Not Allowed
var c : IB = <example> "test";

因此,虽然您建议a变量的加宽类型,但它等同于C#,因为编译器知道aexample以及{{{ 1}}。不同之处在于此类型信息是结构性的,而非名义性的。 IA也可能与您应用程序中的许多其他类型兼容 - 特别是如果您是接口隔离原则的倡导者。

禁止在类型为a的变量中直接使用IA会阻止您分配不兼容的类型。首先检查类型,但结构也可用。

另一位程序员完全有可能将IB分配给{a: 'x'}变量。此时,您会很高兴TypeScript警告您使用上面的代码无法将类型扩展为a,因为它是正确的,它只是防止了运行时错误。

您可以通过以下方式实现您想要的目标:

  1. 声明example属于a类型 - 这就是您打算如何使用变量,所以非常诚实。
  2. 当您要使用example中的成员时,使用类型安全扩展名aIA声明为example类型。扩展由编译器检查。
  3. example声明为a类型。如果您认为自己比编译器更了解,则可以完全控制并负责。
  4. 因此,您可以选择要从编译器中获取的控制级别。我的推荐是上面的第一个选项 - 使用反映您将如何实际使用该值的类型。这与您在C#中习惯使用的内容最接近,就像您有一个接受any的方法一样,您不会开始尝试将其转换为方法内的IEnumerable。如果您需要一个列表,您可以确保方法签名要求一个(同时确认询问一般类型并返回特定类型的原则)。