我正在玩TypeScript和接口。我有以下代码
interface Control {
name: string;
onSelect():string;
}
class Button {
name:string="button";
onSelect = function() {
return "hello";
}
}
var a:Button = new Button();
var b:Control = {"name": "arbitrary", "onSelect": () => { return "ahoy!"; }};
var trigger = function(c:Button) {
console.log(c.name, "says", c.onSelect());
}
trigger(a);
trigger(b);
编译并运行而不抱怨。任何人都可以解释为什么我的trigger
函数接受b
,即使它希望获得Button
类型而b
类型为Control
。
即使Button
要明确实施Control
,我也要求Button
而不是Control
。出于所有预期目的,Button
可能包含其他成员。
TypeScript是否因为它们在结构上相同而推断实现?你是否可以通过一个预期实现类的接口? (不应该是相反的方式吗?)
答案 0 :(得分:4)
如TypeScript documentation on interfaces:
中所述TypeScript的核心原则之一是类型检查侧重于值所具有的“形状”。这有时被称为“鸭子打字”
如果它看起来像鸭子,像鸭子一样游泳,那么它很可能是鸭子。
换句话说,TypeScript检查提供的对象或类型的形状(方法和属性)。如果提供的对象包含接口描述的所有属性和方法,则该对象很可能被视为与所描述的接口兼容的对象。
在您的示例中,您的界面和类看起来完全相同,因此TypeScript会将您的对象视为与所描述的界面兼容。
如果您examine the generated JavaScript,请注意根本没有提及您的界面 - 这是因为TypeScript接口本质上是开发人员提供的类型元数据,可帮助TypeScript验证类型兼容性。
答案 1 :(得分:1)
interface
和class
都具有相同的实现,因此在期望Button
时,您传入兼容对象(具有返回字符串的名称和返回a的onSelect函数)字符串)
如果您将另一个属性添加到Button
,例如greeting: string
,则trigger(b)
上的错误会导致其无效。
interface Control {
name: string;
onSelect:() => string; // this is another way to write function that returns a string
}
class Button implements Control {
name:string="button";
onSelect = function() {
return "hello";
}
greeting: string; // adding this will cause trigger(b) to fail
}