概述
typescript 的接口只会关注值的外形,实际就是类型(条件)的检查,只要满足就是被允许的。
接口描述了类的公共部分。
接口
interface Person {
firstName: string;
lastName: string;
}
function greeter(person: Person) {
return 'Hello, ' + person.firstName + ' ' + person.lastName;
}
var user = {
firstName: 'Jane',
lastName: 'User'
};
document.body.innerHTML = greeter(user);
// 可选属性
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
let newSquare = { color: 'white', area: 100 };
if ( config.width ) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({color: 'black'});
// 只读属性(只能在对象刚刚创建的时候修改其值)
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error
// ReadonlyArray<T>
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error
ro.push(5); // error
ro.length = 100; // error
a = ro; // error
// 可以使用断言重写
a = ro as number[];
// const vs readonly
// 作为变量则用 const
// 作为属性则使用 readonly
// 对于会额外带有任意数量的其他属性,最佳方法是添加一个字符串索引签名
// 一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性,如下代码,即string、number为any的子属性
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any; // 字符串索引签名
}
接口(函数类型)
interface SearchFunc {
// 定义调用签名
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
if ( result == -1 ) {
return false;
} else {
return true;
}
}
// 对于函数类型的类型检查,函数的参数名不需要与接口定义的名字相匹配,但是要求对应位置上的参数类型是兼容的。
接口(可索引的类型)
// 当用 number 去索引 StringArray 时会得到 string 类型的返回值
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ['Bob', 'Fred'];
let myStr: string = myArray[0];
// 防止给索引赋值
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ['Alice', 'Bob'];
myArray[2] = 'Mallory'; // error
// 确保所有属性与其返回值类型相匹配
interface NumberDictionary {
[index: string]: number;
length: number;
name: string; // 错误,name的类型不是索引类型的子类型
}
类类型
// 强制一个类去符合某种契约
interface ClockInterface {
currentTime: Date;
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
// 在接口中描述一个方法,在类中实现它
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
// 类静态部分与实例部分的区别
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new cotr(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);
扩展接口
和类一样,接口也可以相互扩展。能够从一个接口里复制成员到另一个接口里,更灵活地将接口分割到可重用的模块里。
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;
混合类型
// 一个对象可以同时做为函数和对象使用,并带有额外的属性
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function() { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
接口继承类
当接口继承类类型时,它会继承类的成员但不包括其实现。接口同样会继承到类的private和protected成员。意味着这个接口只能被这个类或其子类所实现。
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control {
select() { }
}
class TextBox extends Control {
select() { }
}
class Image {
select() { }
}
class Location {
select() { }
}