TypeScript 的核心原则之一是对值所具有的结构进行类型检查。它有时被称做“鸭式辨型法”或“结构性子类型化”。 在 TypeScript 里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。
类静态部分与实例部分的区别
当你操作类和接口的时候,你要知道类是具有两个类型的:静态部分的类型和实例的类型。 你会注意到,当你用构造器签名去定义一个接口并试图定义一个类去实现这个接口时会得到一个错误:
interface ClockConstructor {
new (hour: number, minute: number)
}
// error
class Clock implements ClockConstructor {
currentTime: Date
constructor(h: number, m: number) { }
}
这里因为当一个类实现了一个接口时,只对其实例部分进行类型检查。constructor
存在于类的静态部分,所以不在检查的范围内。
类类型的例子
我们定义了两个接口, ClockConstructor
为构造函数所用和 ClockInterface
为实例方法所用。 为了方便我们定义一个构造函数 createClock
,它用传入的类型创建实例。
// 定义实例接口
interface ClockInterface {
tick()
}
// 定义构造器接口
interface ClockConstructor {
new(hour: number, minute: number): ClockInterface
}
/**
* 定义工厂函数
* @param ctor 传入时钟类
* @param hour 小时
* @param minute 分钟
*/
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 toc')
}
}
// 创建实例
let digital = createClock(DigitalClock, 12, 17)
let analog = createClock(AnalogClock, 6, 31)
因为 createClock
的第一个参数是 ClockConstructor
类型,在 createClock(AnalogClock, 7, 32) 里,会检查 AnalogClock
是否符合构造函数签名
继承接口
// 继承接口
// 定义类
interface Shape {
color: string
}
interface PenStroke {
penWidth: number
}
// 继承Shape和PenStroke 用 , 分割,同时继承
interface Square extends Shape, PenStroke {
sideLength: number
}
let square = {} as Square
square.color = 'blue'
square.sideLength = 10
square.penWidth = 5.0
混合类型
一个对象可以同时做为函数和对象使用,并带有额外的属性
interface Counter {
(start: number): string,
interval: number,
reset(): void
}
function getCounter(): Counter {
let counter = (function (start: number) {
}) as Counter
counter.interval = 100
counter.reset = function () {
}
return counter
}
let c = getCounter()
c(1)
c.reset()
c.interval = 5.0
接口继承类
class Control {
private state: any
}
interface SelectableControl extends Control {
select()
}
class Button extends Control implements SelectableControl {
select() {
}
}
class TextBox extends Control implements SelectableControl {
select() {
}
}
// Error:“ImageC”类型缺少“state”属性。
class ImagesC implements SelectableControl {
select(){
}
}
在上面的例子里,SelectableControl
包含了 Control
的所有成员,包括私有成员 state
。 因为 state
是私有成员,所以只能够是 Control
的子类们才能实现 SelectableControl
接口。 因为只有 Control
的子类才能够拥有一个声明于Control
的私有成员 state
,这对私有成员的兼容性是必需的。
在 Control
类内部,是允许通过 SelectableControl
的实例来访问私有成员 state
的。 实际上,SelectableControl
接口和拥有 select
方法的 Control
类是一样的。Button
和 TextBox
类是 SelectableControl
的子类(因为它们都继承自Control
并有 select
方法),但 ImageC
类并不是这样的。
网友评论