接口的定义
接口是对行为的抽象,而具体如何实现需要由类去实现。接口除了用于对类的一部分行为进行抽象外,也常用于对对象的形状进行描述。
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
上面定义了一个了一个接口Person,并定义了一个变量tom为对应的接口类型。 接口一般首字母大写。有的编程语言中会建议接口的名称加上 I 前缀。
接口的作用
确保数据结构的一致性。接口作为一种约束,通过定义一个接口,约定了变量、类、函数应该按照什么样的格式进行声明,实现多人合作的一致性。ts编译器依赖接口做类型检查,最终编译为js后,接口将会被移除。
接口的基础篇
1. 赋值的时候,变量的形状必须和接口的形状保持一致。
定义接口的时候,不仅仅可以有属性,也可以有方法。当我们定义一个对象是该接口类型时,该对象必须包含对应的属性和方法(可选属性除外)。少了或者多了一些属性,编译都不会通过。
如上面的例子中,如果这样定义tom,将会报错
let tom: Person={
name:'wang'
}
2.可选属性(即?标识)
上面提到一个变量或对象是对应的接口类型,就必须实现接口中所有的属性和方法,但实际在开发过程中,我们为了提高接口的灵活性,在设计接口的时候,会将某些属性或方法设计为可选的,可选属性的作用就是在实际实现接口的时候,想实现可以实现,不想实现也没关系,如果该属性存在,还能约束其类型。
interface Person {
name:string,
age?:number,
say ?():void
}
定义了一个Person接口,增加了age属性和say方法,两个都是可选的
注意:可选属性如果没有赋值,那么获取到的值是undefined; 对于可选方法,必须先进行判断,再调用,否则会报错;
3.只读属性(readonly)
如果没有特别声明,在接口中定义的属性可读可写,但如果我们希望对象中的一些字段只能在创建的时候被赋值,可以在其前面加上readonly,后面如果进行强制修改,会报错。
interface Person {
name:string,
readonly sex:string,
age?:number,
say ?():void
}
const stu: Person = {
name:'wangzhaoxia',
sex:'man' //只能在初始化的时候赋值
}
stu.sex='feman' // 会提示错误,只读属性不能被赋值
接口的进阶篇
1.函数类型
在上面我们约定了变量(对象)的属性类型,接下来我们来看下如何用interface来规范其函数类型,函数类型的接口里面需要列出参数列表以及函数返回值的类型
interface GetStr {
(x:number,y:number):string;
}
const stu: GetStr = (gradeNum:number,classNum:number) :string =>{
return `${gradeNum}年级${classNum}班级`
}
// ts类型系统默认推论可以不必写参数类型定义,即可以写成下面这样:
const stu: GetStr = (gradeNum,classNum)=>{
return `${gradeNum}年级${classNum}班级`
}
2.数组类型(可索引类型)
它描述了对象索引的类型,还有相应的索引返回值类型。即通过索引得到的类型,如通过下标获取数组arr[2]的值。索引器的类型只能是number或string
// 数字索引类型
interface stringArr {
[index:number]:string //[index:number]是索引器(索引签名),string是该数组元素类型
}
let strArr:stringArr=['wang','chen','jiang']
let str:string=strArr[0]
console.log(str)
// 字符串索引类型
interface ColorMap {
[index: string]: string;
}
let colorMap: ColorMap;
colorMap = {
a: 'Red',
b: 'Blue',
c: 'Green'
};
console.log(colorMap.a,colorMap['a'])
在同时使用两种类型的索引时,数字索引的返回值必须是字符串索引返回值类型的子类型
interface ColorMap {
[x:number]:number, //这里会报错,返回值类型必须是string类型
[index: string]: string;
}
3.类类型
所谓类类型,即把公共的部分抽象成为接口,通过类来实现接口,而不是把接口直接拿来用
interface Clock {
time:Date,
setTime(d:Date):void
}
class Time implements Clock{
time:Date
setTime(d:Date):void{
this.time=d
}
}
4.接口的继承
接口可以通过extends来实现继承(继承一个或多个都可以),方便将一个接口里的成员复制到另一个接口里。
interface People{
name: string;
}
interface Student extends People{
age: number;
}
let stu: Student = {name: '小明', age: 12 };
// 一个接口可以继承多个接口, 使用 ,分隔
interface Shape {
color: string;
}
interface Pen {
width: number;
}
interface Square extends Shape, Pen {
length: number;
}
let c=<Square>{} // 注意这里的写法:创建一个对象,并指定泛型
c.color='red'
c.width=100
c.length=100
console.log(c,typeof c)
5.混合类型
即在一个接口中定义多种类型,比如属性、函数。
interface People{
(): void;
sex: string;
age: number;
sayHi(): void;
}
// 这边需要用到类型断言 as 或者 <>
function getPeople(): People{
let people: People = (() => {}) as People;
// let people=<People> function(){}
people.sex = 'feman';
people.age = 23;
people.sayHi = () => { console.log('Hi!'+people.sex) }
return people
}
let p = getPeople();
p.age = 24;
p.sex='man'
console.log(p.sex)
console.log('---')
console.log(p.sayHi())