在TypeScript手册中,在“使用类作为接口”一节中,有一个继承类的接口示例。
class Point { ... }
interface Point3d extends Point {...}
这种情况何时有用?你有任何实际的例子吗?
在TypeScript手册中,在“使用类作为接口”一节中,有一个继承类的接口示例。
class Point { ... }
interface Point3d extends Point {...}
这种情况何时有用?你有任何实际的例子吗?
以这个课程为例:
class MyClass {
public num: number;
public str: string;
public constructor(num: number, str: string) {
this.num = num;
this.str = str;
}
public fn(arr: any[]): boolean {
// do something
}
}
let a1 = new MyClass(4, "hey");
let a2 = {
num: 3,
str: "hey",
fn: function(arr: any[]): boolean {
// do something
}
}
a1
是MyClass
的一个实例,而a2
只是一个对象,但它们都实现了相同的接口。
接口继承类的关键在于,你可以取出类定义的接口并将其扩展。
也许这只是由于语言本质的可能性,但下面是一个可能有用的示例:
class Map<T> {
private _items: { [key: string]: T };
set(key: string, value: T) { ... }
has(key: string): boolean { ... }
get(key: string): T { ... }
remove(key: string): T { ... }
}
interface NumberMap extends Map<number> {}
interface StringMap extends Map<string> {}
interface BooleanMap extends Map<boolean> {}
function stringsHandler(map: StringMap) { ... }
正如在TypeScript手册的接口部分中描述的那样:
接口继承了基类的私有和受保护成员。这意味着当你创建一个继承带有私有或受保护成员的类的接口时,只有该类或其子类才能实现该接口类型。
这种限制似乎是私有和受保护成员继承的副作用。
class Parent
{
private m_privateParent;
}
interface ISomething extends Parent
{
doSomething(): void;
}
class NoonesChild implements ISomething
{
/**
* You will get error here
* Class 'NoonesChild' incorrectly implements interface 'ISomething'.
* Property 'm_privateParent' is missing in type 'NoonesChild'
*/
doSomething()
{
//do something
}
}
class NoonesSecondChild implements ISomething
{
/**
* Nope, this won't help
* Class 'NoonesSecondChild' incorrectly implements interface 'ISomething'.
* Types have separate declarations of a private property 'm_privateParent'.
*/
private m_privateParent;
doSomething()
{
//do something
}
}
class ParentsChild extends Parent implements ISomething
{
/**
* This works fine
*/
doSomething()
{
//Do something
}
}
我也曾经困惑于“为什么要这样做?”以下是我学到的内容。
如前所述,接口会继承基类的私有和受保护成员。这意味着当你创建一个扩展了带有私有或受保护成员的类的接口时,该接口类型只能由该类或其子类实现。
想象一下,你正在为用户界面实现控件。你需要标准的控件,比如按钮、文本框和标签。
层次结构将会是:
class Control{
private state: any;
}
class Button extends Control{
}
class TextBox extends Control{
}
class Label extends Control{
}
// WARNING: This isn't correct - see rest of post for details.
interface ActivatableControl{
activate(): void;
}
任何实现该接口的内容都可以被视为ActivatableControl,所以让我们更新我们的层次结构:
class Control{
private state: any;
}
interface ActivatableControl{
activate(): void;
}
class Button extends Control implements ActivatableControl{
activate(){}
}
class TextBox extends Control implements ActivatableControl{
activate(){}
}
class Label extends Control{}
如上所述,Label类没有实现ActivatableControl接口。那么一切都好了,对吧?
问题在于,我可以添加另一个实现ActivatableControl接口的类:
class Dishwasher implements ActivatableControl{
activate(){}
}
该接口的目的是为了控制可以被激活,而不是无关的对象。
因此,我真正想要的是指定一个需要某些可激活的控件,而不是其他任何东西的接口。
为了实现这一点,我让我的接口扩展Control,如下所示:
class Control{
private state: any;
}
interface ActivatableControl extends Control {
activate(): void;
}
// Error!
class Dishwasher implements ActivatableControl{
activate(){}
}
class TextBox extends Control {
activate(){}
}
这里是最终版本的层次结构,附带一些代码展示我可以用它做什么:
class Control {
private state: any;
}
interface ActivatableControl extends Control {
activate(): void;
}
class Button extends Control implements ActivatableControl {
activate() { }
}
// Implicitly implements ActivatableControl since it matches the interface and extends Control.
class TextBox extends Control {
activate() { }
}
class Label extends Control {
}
// Error - cannot implement ActivatableControl because it isn't a Control
/*
class Dishwasher implements ActivatableControl {
activate() { }
}
*/
// Error - this won't work either.
// ActivatableControl extends Control, and therefore contains state as a private member.
// Only descendants of Control can implement ActivatableControl.
/*
class Microwave implements ActivatableControl {
private state: any;
activate() { }
}
*/
let button: Button = new Button();
let textBox: TextBox = new TextBox();
let label: Label = new Label();
let activatableControl: ActivatableControl = null;
// I can assign button to activatableControl.
activatableControl = button;
// Same with textBox since textBox fulfills the contract of an ActivatableControl.
activatableControl = textBox;
// Error - label does not implement ActivatableControl
// nor does it fulfill the contract.
//activatableControl = label;
function activator(activatableControl: ActivatableControl){
// I can assume activate can be called
// since ActivatableControl requires that activate is implemented.
activatableControl.activate();
}
请看下面的例子。
// This class is a set of premium features for cars.
class PremiumFeatureSet {
private cruiseControl: boolean;
}
// Only through this interface, cars can use premium features.
// This can be 'licensed' by car manufacturers to use premium features !!
interface IAccessPremiumFeatures extends PremiumFeatureSet {
enablePremiumFeatures(): void
}
// MyFirstCar cannot implement interface to access premium features.
// Because I had no money to extend MyFirstCar to have PremiumFeatureSet.
// Without feature, what's the use of a way to access them?
// So This won't work.
class MyFirstCar implements IAccessPremiumFeatures {
enablePremiumFeatures() {
}
}
// Later I bought a LuxuryCar with (extending) PremiumFeatureSet.
// So I can access features with implementing interface.
// Now MyLuxuryCar has premium features first. So it makes sense to have an interface to access them.
// i.e. To implement IAccessPremiumFeatures, we need have PremiumFeatureSet first.
class MyLuxuryCar extends PremiumFeatureSet implements IAccessPremiumFeatures {
enablePremiumFeatures() {
// code to enable features
}
}
typedef
,用于区分继承。 - syntheticgio