在开始之前,当您扩展一个类时,您需要使用extends
关键字。您可以扩展一个类并实现一个接口。此内容更多详细说明请参见本文后面的附注。
class SpecialTest extends Test {
此外,要注意区分string
和String
,因为这可能会让你犯错。你的类型注释几乎肯定应该是string
(小写)。
最后,你不需要手动分配构造函数参数,因此原始代码:
class Test {
private name: string;
constructor(name: string) {
this.name = name;
}
}
更好地表达为:
class Test {
constructor(private name: string) {
}
}
现在您可以从多种解决方案中选择适合您的问题。
受保护成员
将 name
成员设置为受保护,然后您就可以在子类中使用它:
class Test {
protected name: string;
constructor(name: string) {
this.name = name;
}
getName() {
return this.name;
}
setName(name: string): void {
this.name = name;
}
}
class SpecialTest extends Test {
getName(): string {
return '';
}
setName(name: string): void {
}
}
接口
这是我认为最符合您需求的解决方案。
如果将公共成员提取到接口中,您应该能够将这两个类视为该接口(无论是否显式使用 implements
关键字 - TypeScript 是结构类型)。
interface SomeTest {
getName(): string;
setName(name: string): void;
}
如果您希望的话,可以明确地实现它:
class SpecialTest implements SomeTest {
private name: string;
getName(): string {
return '';
}
setName(name: string): void {
}
}
现在您的代码可以依赖于接口而不是具体类。
将类用作接口
从技术上讲,将一个类作为接口进行引用是可行的,但如果使用implements MyClass
则会遇到问题。
首先,对于任何以后必须阅读您代码的人(包括未来的您),您都正在添加不必要的复杂性。您还在使用一种模式,这意味着您需要小心关键字。在继承的类被更改时,意外使用extends
可能会导致棘手的错误。维护人员将需要成为有眼力的鹰眼,了解使用了哪个关键字。而所有这些只是为了保留结构语言中的名义惯例。
接口是抽象的,不太可能改变。类更加具体,更容易改变。将类用作接口破坏了依赖于稳定抽象概念的整个概念...而转而使您依赖于不稳定的具体类。
考虑在程序中出现的“将类用作接口”的泛滥。类的更改(比如我们添加一个方法)可能会无意中导致更改波及广泛...由于输入不包含甚至没有使用的方法,因此程序的多少部分现在会拒绝输入?
更好的替代方案(当不存在访问修饰符兼容性问题时)是...
从类中创建一个接口:
interface MyInterface extends MyClass {
}
或者,在第二个类中根本不引用原始类。允许结构类型系统检查兼容性。
顺便提一下......根据您的TSLint配置,弱类型(例如仅包含可选类型的接口)将触发no-empty-interface
规则。
私有成员的特例
这些方法(使用类作为接口、从类生成接口或结构类型)都无法解决私有成员的问题。这就是为什么解决真正问题的解决方案是创建一个带有公共成员的接口。
在私有成员的特定情况下,比如在问题中,让我们想想如果继续使用原始模式会发生什么?自然的结果将是为了保持使用类作为接口的模式,成员的可见性将被改变,就像这样:
class Test {
public name: string;
constructor(name: string) {
this.name = name;
}
getName() {
return this.name;
}
setName(name: string): void {
this.name = name;
}
}
现在我们正在打破更加成熟的面向对象编程原则。
SpecialTest
实现了Test
,它需要声明私有属性name
吗? - stealththeninja