TypeScript学习笔记之 接口(Interface)

在java中,接口是用来定义一些规范,使用这些接口,就必须实现接口中的方法,并且接口中的属性必须是常量。
javascript中是没有接口的概念的。因此TypeScript在编译成 JavaScript 的时候,全部的接口都会被擦除掉。
而TypeScript的核心之一就是类型检查。 在TypeScript里,接口的做用就是为这些类型命名和为你的代码或第三方代码定义契约并让代码看起来更好理解。javascript

接口的简单使用
以下代码所示,咱们须要给add函数中传入一个对象,若是不使用接口,咱们传入的对象能够有其余属性。php

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});//不报错

用接口来表示,能够看到,咱们先定义个接口,而后把符合接口定义的对象传进去,这样能提升代码可读性。
须要注意的是:
若是咱们不给传进去的对象指定是接口类型的数据,那么传入的对象参数能够包含其余属性,编译器只会检查那些必需的属性是否存在,而且其类型是否匹配。
若是咱们给对象指定是接口类型的数据,那么,对象的属性必须和定义好的接口的必要属性一致。必要属性不能多也不能少。java

/** * 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就无关紧要。web

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);

定义只读数组
只读数组也同样,一旦定义后不能再修改数组svg

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。ui

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

接口的类类型
所谓类类型,就是一个类去实现接口,而不是直接把接口拿来用,这更符合咱们的使用习惯。this

interface IClock{
    /*定义了一个接口 这个接口中有一个属性和一个方法*/
    currentTime:Date;
    getTime(d:Date);
}
/*Time类实现IClock接口*/
class Time implements IClock{
    currentTime:Date;
    getTime(d:Date){
        this.currentTime=d;
    }
}

扩展接口
在TypeScript中,接口跟类同样是能够相互继承的, 这让咱们可以从一个接口里复制成员到另外一个接口里,能够更灵活地将接口分割到可重用的模块里。spa

/*接口能够继承接口 而且能够多继承*/

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;