接口可以用来约束对象、函数以及类的结构和类型。
typescript并没有 “实现” 接口这个概念,而是只关注值的外形,只要传入的对象满足上面的必要条件,那么它就是被允许的。
对象类型接口
interface List {
id: number;
name: string;
}
interface Result {
data: List[];
}
function getResult(result: Result) {
result.data.forEach(item => {
console.log(item.id, item.name);
})
}
let myResult = {
data: [
{id: 1, name: 'Bob', score: 98},
{id: 2, name: 'Carl', score: 87}
]
};
getResult(myResult);
// 1 'Bob'
// 2 'Carl'
类型检查器会查看 getResult 的调用,其传入的参数中包含了三个属性,但是编译器只会检查那些必需的属性是否存在,且其类型是否匹配。所以即使多了一个score属性,也是可以通过编译的。
但是当 getResult 参数传入的是对象字面量,ts不仅会检查必要的属性,还会对额外的参数进行类型检查。
除了把对象字面量赋值给一个变量外,还有3种方法绕过这种检查:
- 使用类型断言
- 可选属性:在属性名字后面加一个?符号
- 字符串索引签名
// 使用类型断言
getResult({data: [{id: 1, name: 'Bob'}, {id: 2, name: 'Carl', score: 98}]} as Result)
// 可选属性
interface List {
id: number;
name: string;
score?: number; // 可选属性
}
// 字符串索引签名
interface List {
id: number;
name: string;
[propName: string]: any; // 字符串索引签名
}
getResult({
data: [{id: 1, name: 'Bob', score: 98}, {id: 2, name: 'Carl', score: 87}]
});
// 1 'Bob'
// 2 'Carl'
索引类型
可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。比如:a[0] 或 a["name"]
定义格式:
interface 接口名 {
[任意字段: 索引类型]: 索引返回值类型;
}
索引签名可以是字符串和数字,也可以同时使用两种类型的索引
// 数字索引
interface StringArray {
[inder: number]: string;
}
let s1: StringArray = ["TypeScript", "Webpack"];
console.log('s1: ', s1); // s1: [ 'TypeScript', 'Webpack' ]
// 字符串索引
interface ScoreMap {
[subject: string]: number;
}
let s2: ScoreMap = {
"Chinese": 99,
"Math": 100
}
console.log('s2: ', s2); // s2: { Chinese: 99, Math: 100 }
// 同时使用字符串和数字索引
interface StudentMap {
[index: number]: string;
[name: string]: string;
}
let s3: StudentMap[] = [
{
1: "678分",
"姓名": "张伟"
},
{
2: "670分",
"姓名": "尔康"
}
]
console.log('s3: ', s3);
// s3: [ { '1': '678分', '姓名': '张伟' }, { '2': '670分', '姓名': '尔康' } ]
如果同时使用字符串索引和数字索引,要么数字索引的返回值类型和字符串索引返回值类型没有继承关系 ,要么数字索引的返回值必须是字符串索引返回值类型的子类型。因为当使用number来索引时,js会将它隐式转换成string,然后再去索引对象。
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
interface Okay {
[x: string]: Animal;
[y: number]: Dog;
}
// Numeric index type 'Animal' is not assignable to string index type 'Dog'.
interface NotOkay {
[x: string]: Dog;
[y: number]: Animal; // 数字索引类型“Animal”不能赋给字符串索引类型“Dog”
}
只读属性
可以在属性名前用 readonly 来指定只读属性
interface Point {
readonly x: number;
readonly y: number;
}
// 可以通过赋值一个对象字面量来构造一个Point。 赋值后,x和y再也不能被改变了。
let p: Point = { x: 3, y: 5};
console.log('p', p); // p { x: 3, y: 5 }
// p.x = 20; // Cannot assign to 'x' because it is a read-only property
typescript 具有 ReadonlyArray<T> 类型,它与 Array<T> 相似,只是把所有可变方法都去掉了。可以确保数组创建后就再也不能修改。
let arr: number[] = [1, 2, 3];
let ro: ReadonlyArray<number> = arr;
ro[0] = 33; // 类型“readonly number[]”中的索引签名仅允许读取
ro.push(4); // 类型“readonly number[]”上不存在属性“push”
ro.length = 99; // Cannot assign to 'length' because it is a read-only property
判断该使用readonly 还是 const 的方法主要是看作为变量还是作为属性,作为变量的话使用 const,作为属性则使用 readonly
函数类型接口
接口还可以用来限制函数的 参数列表 和 返回值类型 。
interface Add {
(base: number, increment: number): number
}
// 调用接口
let add: Add = (x: number, y: number) => x + y;
console.log( add(1, 2) ); // 3
类类型接口
typescript 中的类可以像Java里的接口一样,使用类来实现一个接口,由此来明确的强制一个类去符合某种契约。
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 Counter {
(start: number): string;
interval: number;
reset(): void;
}
var c: Counter;
c(10);
c.reset();
c.interval = 5.0;
继承接口
接口也可以相互继承,可以从一个接口里复制成员到另一个接口里,由此可以更加灵活的将接口分割到可重用的模块里
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square: Square = {
color: 'red',
sideLength: 15
}
console.log('square ', square); // square { color: 'red', sideLength: 15 }
一个接口可以继承多个接口,创建出多个接口的合成接口
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square: Square = {
color: 'red',
penWidth: 6,
sideLength: 15
}
console.log('square ', square); // square { color: 'red', penWidth: 6, sideLength: 15 }
摘抄自Typescript 实战 --- (3)接口