我很惊讶我无法在接口之间进行转换。
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);
答案 0 :(得分:2)
如果你有example
,它会很乐意接受IA
或IB
的类型断言,因为它与这两种类型兼容。
IA
与IB
不兼容,因此如果您尝试使用类型断言,编译器会发出警告。
您可以使用以下方法执行类型安全扩展:
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#,因为编译器知道a
与example
以及{{{ 1}}。不同之处在于此类型信息是结构性的,而非名义性的。 IA
也可能与您应用程序中的许多其他类型兼容 - 特别是如果您是接口隔离原则的倡导者。
禁止在类型为a
的变量中直接使用IA
会阻止您分配不兼容的类型。首先检查类型,但结构也可用。
另一位程序员完全有可能将IB
分配给{a: 'x'}
变量。此时,您会很高兴TypeScript警告您使用上面的代码无法将类型扩展为a
,因为它是正确的,它只是防止了运行时错误。
您可以通过以下方式实现您想要的目标:
example
属于a
类型 - 这就是您打算如何使用变量,所以非常诚实。example
中的成员时,使用类型安全扩展名a
将IA
声明为example
类型。扩展由编译器检查。example
声明为a
类型。如果您认为自己比编译器更了解,则可以完全控制并负责。因此,您可以选择要从编译器中获取的控制级别。我的推荐是上面的第一个选项 - 使用反映您将如何实际使用该值的类型。这与您在C#中习惯使用的内容最接近,就像您有一个接受any
的方法一样,您不会开始尝试将其转换为方法内的IEnumerable
。如果您需要一个列表,您可以确保方法签名要求一个(同时确认询问一般类型并返回特定类型的原则)。