TypeScript中Interface的理解

23次阅读

共计 1644 个字符,预计需要花费 5 分钟才能阅读完成。

背景
在阅读官方文档的时候,遇到了如下代码。
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,而 DigitalClock 和 AnalogClock 这两个类都是由 ClockInterface 这一接口继承来的,并没有实现 ClockConstructor,按照我的理解,这样的代码很显然是不合法的。但这段代码无疑又是正确的,毕竟这是官方示例,又能编译运行通过。
对于 Interface 的理解
既然是官方的示例,还是要从官方文档入手理解。在官方文档对 Interface 的介绍中第一句就写到:“One of TypeScript’s core principles is that type-checking focuses on the shape that values have.”,也就是说,TypeScript 的核心原则是对值的“形状”进行检查。这里的值的形状就是指他所拥有的属性和方法。分析 createClock 的第一个参数,ctor: ClockConstructor,在 TypeScript,他的意思是第一个参数要和 ClockConstructor 这一 Interface 的形状一样。什么叫形状一样?就是要有相同的属性和方法。那 ClockConstructor 有且只有一个构造方法即 new (hour: number, minute: number): ClockInterface(我得吐槽一下 Interface 的构造方法为啥不也用 constructor 啊看起来好不自然啊。)。也就是说,只要你提供一个构造器接受两个数字作为参数,同时构造完成一个符合 ClockInterface 形状的对象,那就是符合要求的。如果这一想法是正确的,那如下的代码应该也能够工作:
class someClock {
constructor(a: number, b: number) {}
tick() {}
}

let testClock = createClock(someClock, 8, 12)
someClock 并未声明 implements ClockInterface,但也能被 createClock 所接受,这也证明了之前的想法,他的要求是参数列表和返回值类型能对的上,达到这个要求就可以被接受。
总结
会产生这样的问题,还是因为把其他语言的思路往 TypeScript 上套了。例如在 JAVA 中,如果采用类似的实现,那么只有显式声明了 implements ClockInterface 的类才能被 creatClock 方法所接受。但解决问题还是要从官方文档入手,理解了“TypeScript 的核心原则之一是对值所具有的结构进行类型检查”这句话,才能更好地学习 TypeScript。

正文完
 0