jvo*_*igt 9 typescript typescript2.0 angular
我试图将Class作为接口用于另一个类.有了这个,我试图完成一个最新的mockClass测试.
这应该是可能的,并且是一种有利的方法,如https://angular.io/guide/styleguide#interfaces中的状态
并在此处演示:将类导出为Angular2中的接口
但奇怪的是我在VSCode 1.17.2中使用Typescript 2.5.3时遇到错误
类SpecialTest中的错误
[ts]
Class 'SpecialTest' incorrectly implements interface 'Test'.
Types have separate declarations of a private property 'name'.
Run Code Online (Sandbox Code Playgroud)
Samplecode:
class Test {
private name: string;
constructor(name: string) {
this.name = name;
}
getName() {
return this.name;
}
setName(name: string): void {
this.name = name;
}
}
class SpecialTest implements Test {
private name: string;
getName(): string {
return '';
}
setName(name: string): void {
}
}
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
编辑:使用string而不是String像@fenton建议的那样
要从类中提取接口,该接口将只包含公共属性而不是类的所有实现细节,您可以将keyof运算符与Pick<Type, Keys>实用程序一起使用。
class Test {
foo: any;
private bar: any;
}
class SepcialTest implements Pick<Test, keyof Test> {
foo: any;
}
Run Code Online (Sandbox Code Playgroud)
Pick<Type, Keys>通过从 Type 中选取一组属性 Keys 来构造一个类型。
[...]
keyof T,索引类型查询运算符。对于任何类型 T,keyof T 是 T 的已知公共属性名称的并集。
在我们开始之前,当您扩展一个类时,您使用extends关键字.您扩展了一个类,并实现了一个接口.在帖子上还有其他注释.
class SpecialTest extends Test {
Run Code Online (Sandbox Code Playgroud)
另外,请注意stringvs,String因为这会让你失望.你的类型注释几乎肯定是string(小写).
最后,您不需要手动分配构造函数参数,因此原始:
class Test {
private name: string;
constructor(name: string) {
this.name = name;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
更好地表达为:
class Test {
constructor(private name: string) {
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以从众多问题的解决方案中进行选择.
使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 {
}
}
Run Code Online (Sandbox Code Playgroud)
这是我认为最符合您需求的解决方案.
如果将公共成员拉入接口,则应该能够将这两个类视为该接口(无论您是否明确使用该implements关键字 - TypeScript是结构化类型).
interface SomeTest {
getName(): string;
setName(name: string): void;
}
Run Code Online (Sandbox Code Playgroud)
如果您愿意,可以明确地实现它:
class SpecialTest implements SomeTest {
private name: string;
getName(): string {
return '';
}
setName(name: string): void {
}
}
Run Code Online (Sandbox Code Playgroud)
您的代码现在可以依赖于接口而不是具体的类.
技术上可以将类作为接口引用,但是在执行此操作之前存在问题implements MyClass.
首先,您为以后需要阅读代码的任何人(包括未来的代码)添加了不必要的复杂性.您还使用了一种模式,这意味着您需要注意关键字.extends当继承的类被更改时,意外使用可能会在将来导致棘手的错误.维护人员需要成为使用关键字的傻瓜.一切都是为了什么?用结构语言保留名义习惯.
接口是抽象的,不太可能改变.类更具体,更容易改变.使用类作为接口破坏了依赖于稳定抽象的整个概念......而是使您依赖于不稳定的具体类.
考虑整个程序中"类作为接口"的扩散.对类的更改(假设我们添加了一个方法)可能会无意中导致更改波动到很远的距离...程序的多少部分现在拒绝输入,因为输入不包含甚至不使用的方法?
更好的选择(当没有访问修饰符兼容性问题时)......
在类外创建一个接口:
interface MyInterface extends MyClass {
}
Run Code Online (Sandbox Code Playgroud)
或者,在第二堂课中根本不要引用原始课程.允许结构类型系统检查兼容性.
旁注......根据您的TSLint配置,弱类型(例如只有可选类型的接口)将触发no-empty-interface-Rule.
这些(使用类作为接口,从类生成接口或结构类型)都不能解决私有成员的问题.这就是为什么解决真正问题的解决方案是创建与公共成员的接口.
在私人成员的特定情况下,例如在问题中,让我们考虑如果我们继续使用原始模式会发生什么?自然结果是保留使用类作为接口的模式,成员的可见性将被更改,如下所示:
class Test {
public name: string;
constructor(name: string) {
this.name = name;
}
getName() {
return this.name;
}
setName(name: string): void {
this.name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
而现在我们正在打破更为既定的面向对象原则.
| 归档时间: |
|
| 查看次数: |
4498 次 |
| 最近记录: |