好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

typescript中的接口

TypeScript的核心原则之一是对值所具有的 结构 进行类型检查,而接口就是用来定义值的结构,接口自身当作类型来用。

 

基本使用

先看一段代码:

function func(obj: { name:  string  }):  void   {
  console.log(  '  hello   '  +  obj.name)
} 

很明显,函数func要求参数是一个包含name属性的对象,name值为string类型。而 { name: string } 就可以被定义为接口,如下:

 interface  objType {  //   定义接口 objType 
  name:  string  
}

function func(obj: objType):   void   {
  console.log(  '  hello   '  +  obj.name)
} 

代码里使用 interface 来定义接口,需要注意的是,不要把它理解为是在定义一个对象,而要理解为 {} 括号包裹的是一个代码块,里面是一 条条声明语句,只不过声明的不是变量的值而是类型。上述代码定义的是最简单的接口结构,只有一个属性时定义成接口或许没必要,但当结构复杂时,接口的用处就会慢慢体现。

 

可选属性

当我们定义一些结构的时候,一些结构对于某些字段的要求是可选的,有这个字段就做处理,没有就忽略。接口里在属性名后面加上 ? 就可以表示这个属性是可选的:

 interface   objType {
  name:   string  
  age ?: number   //   age 是可选的 
 } 

function func(obj: objType):   void   {
  let age  = obj.age ? obj.age :  18  
  console.log(obj.name  +  '   is   '  + age +  '   years old   '  )
} 

 

只读属性

一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用  readonly 来指定只读属性:

 interface   Point {
    readonly  x: number   //   加上readonly前缀,表示只读 
   readonly  y: number   //   同上  
 }

let n: Point  = { x:  3 , y:  5   }

n.x  =  10    //   Cannot assign to 'x' because it is a read-only property. 

 定义只读变量用 const,定义只读属性用 readonly。

 

额外属性检查 

当某接口类型里不存在某个属性时,就不能应用这个属性,否则会报错,例如:

 interface   Point {
  x: number
  y: number
}

let n: Point  = { x:  3 , y:  5 , z:  10  }   //   这里加入了z属性,会报错

  //    Type '{ x: number; y: number; z: number; }' is not assignable to type 'Point'.
  //    Object literal may only specify known properties, and 'z' does not exist in type 'Point'. 

很多时候,我们希望绕过typescript的这个检查,那么有几个方法需要知道:

(1)类型断言

将值断言为Point类型,告诉typescript我们已经自行检查过了,没有问题

let n: Point = { x:  3 , y:  5 , z:  10  }  as  Point

 

(2)字符串索引签名

定义任意属性,属性名是string类型,propName是泛指的属性名,只要不是 x 和 y,就无所谓它的值类型:

 interface   Point {
  x: number
  y: number
  [propName:   string  ]: any
}

let n: Point  = { x:  3 , y:  5 , z:  10  }

 

(3)利用类型兼容性

这个方法说白了就是先把值赋值给一个变量,然后再把这个变量赋值给这个接口类型的变量:

 interface   Point {
  x: number
  y: number
}

let obj  = { x:  3 , y:  5 , z:  10  }  //   需要的值赋值给变量 
let n: Point = obj  //   变量赋值给接口类型变量 

 

函数类型接口

除了描述带有属性的普通对象外,接口也可以描述函数类型。为了使用接口表示函数类型,我们需要给接口定义一个调用签名:

 interface   AddFunc {
  (num1: number, num2: number): number
} 

接口AddFunc要求实现这个接口结构的值须包含一个函数,其函数结构和接口内定义的函数结构一致。如:

 let func: AddFunc
func  =  function(num1:number, num2:number): number {
    return  num1 +  num2
} 

对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。 比如,我们使用下面的代码重写上面的例子:

 let func: AddFunc
func  = function(n1:number, n2:number): number {   //   n1,n2代替num1,num2 
   return  n1 +  n2  
} 

函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的。另外你也可以不指定类型,由typescript推导类型:

 interface   AddFunc {
  (num1: number, num2: number): number
}

let func: AddFunc
func  =  function(n1, n2) {
    return  n1 +  n2
} 

 

可索引的类型接口

接口可以描述那些“可通过索引得到”的类型,如数组 a[1] 或对象 obj["name"],可以同时给索引和值都设置类型,如:

 interface MyArray {
  [index: number]: string
}

const arr: MyArray  = ['Apple', 'Orange' ]

interface MyObject {
  [key: number]: string
}

const obj: MyObject  =  {
   0: 'hello' ,
   1: 'world' 
} 

 

 接口的继承

接口也可以继承,本质上就是从一个接口里复制成员到另一个接口里,更灵活的复用属性。

 //   定义一个 Person 接口,它包含两个属性和一个方法 
 interface Person{
  age:number;
  name:string;
  say():  void  ;
}

  //   定义一个 Teacher 接口,继承 Person 的属性成员,同时拥有自己的 teach 方法 
 interface Teacher extends Person{
  teach():  void  ;
}

  //   使用接口 
const teacher:Teacher =  {
  teach(){},
  age: 25 ,
  name: 'tom' ,
  say(){}
} 

 

混合类型

在 js 中,函数是对象,而对象可以有属性,所以有时一个对象,它既是一个函数,也包含一些属性,如这个计数器函数:

 function   countUp(){
    return  ++ countUp.count
}
countUp.count  = 0 

console.log(countUp())   //   1 
console.log(countUp())  //   2 

 

现在来使用混合类型接口来定义上面 countUp 类型:

 interface Counter{
  ():  void  ;
  count:number
}

  function   getCounter():Counter{
  const c  = ()=> {
    c.count ++ 
  }
  c.count  = 0
   return   c
}

const counter:Counter  =  getCounter()

counter()
console.log(counter.count)
counter()
console.log(counter.count)
  

 

以上就是接口的相关内容,接口中还有涉及类的一些内容,后面写到类相关时再说。

查看更多关于typescript中的接口的详细内容...

  阅读:51次