在java中,接口是用来定义一些规范,使用这些接口,就必须实现接口中的方法,而且接口中的属性必须是常量。
javascript中是没有接口的概念的。所以TypeScript在编译成 JavaScript 的时候,所有的接口都会被擦除掉。
而TypeScript的核心之一就是类型检查。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约并让代码看起来更好理解。
接口的简单使用
如下代码所示,我们需要给add函数中传入一个对象,如果不使用接口,我们传入的对象可以有其他属性。
function add(num:{x:number,y:number}){
console.log(num.x+num.y);
}
let n={x:1,y:2,z:3};//这里我们的对象只要包含必要属相且值类型正确即可,允许存在其他属性
add(n);//不报错
// add({x:1,y:2,z:2})//报错,会提示z不存在
add({x:1,y:2});//不报错
用接口来表示,可以看到,我们先定义个接口,然后把符合接口定义的对象传进去,这样能提高代码可读性。
需要注意的是:
如果我们不给传进去的对象指定是接口类型的数据,那么传入的对象参数可以包含其他属性,编译器只会检查那些必需的属性是否存在,并且其类型是否匹配。
如果我们给对象指定是接口类型的数据,那么,对象的属性必须和定义好的接口的必要属性一致。必要属性不能多也不能少。
/**
* Created by yzq on 2017/1/12.
*/
interface num{
x:number;
y:number;
}
function add(n:num){
console.log(n.x+n.y);
}
let n={x:1,y:2,z:3};
let n1:num={x:1,y:2};//如果我们将n1指定为num类型的数据,那么,该对象所包含的属性必须跟定义好的接口完全一致。不能多也不能少。
// let n2:num={x:1};//错误,缺少y属性
// let n3:num={x:1,y:2,z:3};//错误,没有找到z属性,当我们将对象字面量赋值给变量或作为参数传递的时候。TypeScript会进行额外属性检查。如果一个对象字面量存在任何“目标类型”不包含的属性时,就会报错。
add(n);//不报错
add(n1);//不报错
add(n2);
add(n3);
// add({x:1,y:2,z:2})//报错,会提示z不存在,额外的属性检查
add({x:1,y:2});//不报错
接口的可选属性
在实际应用中,接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。在这种个情况下可以是用接口的可选属性去定义。
如下代码所示,name和age被定义为可选属性,那么在传对象的时候name和age就可有可无。
interface Person{
name?:string;
age?:number
}
function getInfo(p:Person){
console.log(p.name);
console.log(p.age);
}
let student={}
// let student={name:"yzq"}
// let student={name:"yzq",age:23}
getInfo(student);
接口的只读属性
如果我们希望对象属性只能在对象刚刚创建的时候修改其值。 我们可以在属性名前用 readonly来指定只读属性。
interface Point{
readonly x:number;
readonly y:number;
}
function getPoint(p:Point){
console.log(p.x);
console.log(p.y);
}
let point:Point={x:1,y:2};
// point.x=2;//错误 这里不能再子修改值
getPoint(point);
定义只读数组
只读数组也一样,一旦定义后不能再修改数组
let a:ReadonlyArray<number> =[1,2,3,4,5];
// a[0]=2;//不能再修改该数组
// a.length=20;
接口的函数类型
接口可以描述javascript的任何对象,不仅能描述对象的属性类型,当然也能描述对象的函数类型。
如下代码所示,接口描述了这个函数的参数类型和返回值类型
interface getStr {
/*在这里我们描述了这个接口有个函数 这个函数传进去2个number类型的参数 然后返回一个string类型的数据*/
(x: number, y: number): string;
}
let myStr : getStr;
myStr = function (gradeNum: number, classNum: number) {
return `${gradeNum}年级${classNum}班`;
}
console.log(myStr(2,8));//2年级8班
接口的数组类型(可索引的类型)
跟接口描述函数类型差不多,我们也可以描述那些能够“通过索引得到”的类型,比如通过下标获取数组中的值 a[2];需要注意的是,索引器的类型只能为 number 或者 string。
interface stringArr{
/*描述的一个数组 这个数组里面的元素是string类型 并且只能通过number类型来索引 [index:number]是索引器 string是该数组元素类型*/
[index:number]:string;
// age:number;//需要注意的是,当我们将这个接口是数组类型时,那么,接口中定义的其它属性的类型都必须是该数组的元素类型。 这里的number类型是报错的
}
let strArr:stringArr;
strArr=["1","2"];
// strArr.name="3";
let str:string=strArr[0];
console.log(str);//打印1
接口的类类型
所谓类类型,就是一个类去实现接口,而不是直接把接口拿来用,这更符合我们的使用习惯。
interface IClock{
/*定义了一个接口 这个接口中有一个属性和一个方法*/
currentTime:Date;
getTime(d:Date);
}
/*Time类实现IClock接口*/
class Time implements IClock{
currentTime:Date;
getTime(d:Date){
this.currentTime=d;
}
}
扩展接口
在TypeScript中,接口跟类一样是可以相互继承的, 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。
/*接口可以继承接口 并且可以多继承*/
interface shape{
color:string;
}
interface pen extends shape{
width:number;
}
let circle=<pen>{};//注意这里的写法,创建一个对象并指定泛型
circle.color="red";//这里可以获取color属性
circle.width=2;//有width属性
一个接口可以继承多个接口,创建出多个接口的合成接口。
/*接口可以继承接口 并且可以多继承*/
interface shape{
color:string;
}
interface pen extends shape{
width:number;
}
interface Circle extends shape,pen{
point:number[];
}
let c=<Circle>{};//注意这里的写法,创建一个对象并指定泛型
c.point=[1,2];
c.color="red";
c.width=1;
混合类型
所谓的混合类型就是在一个接口中定义多种类型,比如属性,函数,数组等。
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;