1. 类实现接口
与C#或Java里接口的基本作用一样,TS也能够用它来明确的强制一个类去符合某种 契约 。我们也是用implements 关键字来实现一个接口:
interface UserInterface {username: string;getName(),setName(username: string);}class User implements UserInterface {username: string;getName() {return this.username}setName(username: string) {this.username = username}constructor(username: string) { }}
实现接口,包括实现接口中的属性和方法,上例中 setNaem 就是一个需要实现的方法。
接口描述了类的公共部分,而不包括私有部分。 它不会帮你检查类是否具有某些私有成员。
类静态部分与实例部分的区别
这一部分在官网说的很绕,简单来说就是:类对接口的实现就是在说明这个类的实例会有什么。也就是说当对象被 new 出来之后会有什么。而不是说这个类class里会有什么。
其中 class内的部分就是类静态部分,new 出来之后的实例就是实例部分。检查器只对实例部分进行检查,不会检查静态部分。(虽然错误会直接反应在类定义处)
所以,当我们在接口中定义构造函数签名(也就是 new 方法) 并且用类去实现它的时候,检查器会始终报错,因为类的实例中,不可能有 new 方法(或构造方法),而接口中却说实例里会有 new 方法(恼),这就产生了矛盾,所以报错:
interface UserConstructor {// constructor(): void // 一个构造器签名new(username: string) // 一个构造器签名}// 以下,始终错误class UserInfo implements UserConstructor {constructor() { }}

所以,如果一个接口中定义了构造器签名,那么就不要直接用类去实现它。
解决方法
如果你执意要定义构造器类型的接口,那么你就不应该直接用类去实现它,而是作为一个变量,让变量调用new方法来返回一个实例:
interface UserConstructor {// constructor(): void // 一个构造器签名new(username: string): UserInfo // 一个构造器签名}class UserInfo {constructor(public username: string) {this.username = username}}let userConstruct: UserConstructor = UserInfo // 类类型是静态的,类型检查不会生效,所以将类类型赋值给接口类型也不会报错let user = new userConstruct("ricky")
或者,你也可以将其封装为一个可复用的方法:
interface ClockConstructor {new (hour: number, minute: number): ClockInterface;}interface ClockInterface {tick();}function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {return new ctor(hour, minute);}class DigitalClock implements ClockInterface {constructor(h: number, m: number) { }tick() {console.log("beep beep");}}class AnalogClock implements ClockInterface {constructor(h: number, m: number) { }tick() {console.log("tick tock");}}let digital = createClock(DigitalClock, 12, 17);let analog = createClock(AnalogClock, 7, 32);
因为createClock的第一个参数是ClockConstructor类型,在createClock(AnalogClock, 7, 32)里,会检查AnalogClock是否符合构造函数签名。
2. 接口继承接口
和类一样,接口也可以相互继承。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。同样使用 extends 关键字:
interface Shape {color: string;}interface Square extends Shape {sideLength: number;}let square = <Square>{};square.color = "blue";square.sideLength = 10;
一个接口可以继承多个接口,创建出多个接口的合成接口。
interface Shape {color: string;}interface PenStroke {penWidth: number;}interface Square extends Shape, PenStroke {sideLength: number;}let square = <Square>{};square.color = "blue";square.sideLength = 10;square.penWidth = 5.0;
3.接口继承类
是的,你没有看错,TM接口还能继承类了,接口不是更抽象的类吗?竟然还tm能继承类的。(吐槽)
介绍
当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的private和protected成员。 这意味着当一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement):
class Control {private state: any;}// 接口继承类interface SelectableControl extends Control {select(): void;}// 子类,可以实现接口class Button extends Control implements SelectableControl {select() { }}// 错误:不是子类,“Image”类型缺少“state”属性。class Image implements SelectableControl {select() { }}
当然,如果类中没有私有或受保护的成员变量,那么该接口可以被任意实现。
class Control {public state: any;}// 接口继承类interface SelectableControl extends Control {select(): void;}// 非子类也能实现没有继承到私有或受保护成员的接口class Image implements SelectableControl {select() { }}
