TypeScript 中接口详解


Posted in Javascript onJune 19, 2015

在 TypeScript 中,接口是用作约束作用的,在编译成 JavaScript 的时候,所有的接口都会被擦除掉,因为 JavaScript 中并没有接口这一概念。

先看看一个简单的例子:

function printLabel(labelledObj: { label: string }) {
  console.log(labelledObj.label);
}

var myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

那么在该方法中,labelledObj 的类型就是 {label: string},看上去可能有点复杂,但我们看见看看下面 myObj 的声明就知道,这是声明了一个拥有 size 属性(值为 10)和 label 属性(值为 "Size 10 Object")的对象。所以方法参数 labelledObj 的类型是 {label: string} 即表明参数拥有一个 string 类型的 label 属性。

但是,这么写的话,这个方法看上去还是有点让人糊涂。那么就可以用接口(interface)来定义这个方法的参数类型。

interface LabelledValue {
  label: string;
}

function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}

var myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

可选属性
有些时候,我们并不需要属性一定存在,就可以使用可选属性这一特性来定义。

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
  var newSquare = { color: "white", area: 100 };
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

var mySquare = createSquare({ color: "black" });

那么我们就传入了实现一个 SquareConfig 接口的对象入 createSquare 方法。

既然完全是可有可无的,那么为什么还要定义呢?对比起完全不定义,定义可选属性有两个优点。1、如果存在属性,能约束类型,这是十分关键的;2、能得到语法智能提示,假如误将方法体中 color 写成 collor,那么编译是不通过的。

方法类型

在 JavaScript 中,方法 function 是一种基本类型。在面向对象思想中,接口的实现是靠类来完成的,而 function 作为一种类型,是不是能够实现接口呢?答案是肯定的。

在 TypeScript 中,我们可以使用接口来约束方法的签名。

interface SearchFunc {
 (source: string, subString: string): boolean;
}

var mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
 var result = source.search(subString);
 if (result == -1) {
  return false;
 }
 else {
  return true;
 }
}

上面代码中,我们定义了一个接口,接口内约束了一个方法的签名,这个方法有两个字符串参数,返回布尔值。在第二段代码中我们声明了这个接口的实现。

需要注意的是,编译器仅仅检查类型是否正确(参数类型、返回值类型),因此参数的名字我们可以换成别的。

var mySearch: SearchFunc;
mySearch = function(src: string, sub: string) {
 var result = src.search(sub);
 if (result == -1) {
  return false;
 }
 else {
  return true;
 }
}

这样也是能够编译通过的。

数组类型
在上面我们在接口中定义了方法类型,那么,数组类型又应该如何定义呢?很简单。

interface StringArray {
 [index: number]: string;
}

var myArray: StringArray;
myArray = ["Bob", "Fred"];

那么 myArray 就是一个数组,并且索引器是 number 类型,元素是 string。

在接口的定义里面,索引器的名字一般为 index(当然也可以改成别的,但一般情况下都是保持名字为 index)。所以改成

interface StringArray {
 [myIndex: number]: string;
}

var myArray: StringArray;
myArray = ["Bob", "Fred"];

也是 ok 的。

需要注意的是,索引器的类型只能为 number 或者 string。

interface Array{
  [index: number]: any;
}

interface Dictionary{
  [index: string]: any;
}

上面两段都是可以编译通过的。

最后还有一点要注意的是,如果接口已经是数组类型的话,接口中定义的其它属性的类型都必须是该数组的元素类型。例如:

interface Dictionary {
 [index: string]: string;
 length: number;  // error, the type of 'length' is not a subtype of the indexer
}

那么将无法编译通过,需要将 length 改成 string 类型才可以。

使用类实现接口
一般情况下,我们还是习惯使用一个类,实现需要的接口,而不是像上面直接用接口。

interface ClockInterface {
  currentTime: Date;
}

class Clock implements ClockInterface {
  currentTime: Date;
  constructor(h: number, m: number) { }
}

在 TypeScript 中,使用 class 关键字来声明了,这跟 EcmaScript 6 是一样的。

另外,我们可以使用接口来约束类中定义的方法。

interface ClockInterface {
  currentTime: Date;
  setTime(d: Date);
}

class Clock implements ClockInterface {
  currentTime: Date;
  setTime(d: Date) {
    this.currentTime = d;
  }
  constructor(h: number, m: number) { }
}

在 TypeScript 中,我们可以为接口定义构造函数。

interface ClockInterface {
  new (hour: number, minute: number);
}

接下来天真的我们可能会接着这么写:

interface ClockInterface {
  new (hour: number, minute: number);
}

class Clock implements ClockInterface {
  currentTime: Date;
  constructor(h: number, m: number) { }
}

这是不行的!!!因为构造函数是 static(静态)的,而类仅能够实现接口中的 instance(实例)部分。

那么这个接口中定义的构造函数岂不是没作用?既然 TypeScript 提供了这项功能,那么肯定不会是没作用的。声明的方法比较特殊:

interface ClockStatic {
  new (hour: number, minute: number);
}

class Clock {
  currentTime: Date;
  constructor(h: number, m: number) { }
}

var cs: ClockStatic = Clock;
var newClock = new cs(7, 30);

正常情况下我们是写 new Clock 的,这里就将 Clock 类指向了 ClockStatic 接口。需要注意的是,newClock 变量的类型是 any。

继承接口
像类一样,接口也能实现继承,使用的是 extends 关键字。

interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

var square = <Square>{};
square.color = "blue";
square.sideLength = 10;

当然也能继承多个接口。

interface Shape {
  color: string;
}

interface PenStroke {
  penWidth: number;
}

interface Square extends Shape, PenStroke {
  sideLength: number;
}

var square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

需要注意的是,尽管支持继承多个接口,但是如果继承的接口中,定义的同名属性的类型不同的话,是不能编译通过的。

interface Shape {
  color: string;
  test: number;
}

interface PenStroke {
  penWidth: number;
  test: string;
}

interface Square extends Shape, PenStroke {
  sideLength: number;
}

那么这段代码就无法编译通过了,因为 test 属性的类型无法确定。

同时使用上面所述的类型
如果仅能单一使用某种类型,那么这接口也未免太弱了。但幸运的是,我们的接口很强大。

interface Counter {
  (start: number): string;
  interval: number;
  reset(): void;
}

var c: Counter;
c(10);
c.reset();
c.interval = 5.0;

这样就使用到三种类型了,分别是方法(接口自己是个方法)、属性、方法(定义了方法成员)。

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
JS中动态添加事件(绑定事件)的代码
Jan 09 Javascript
jQuery调用WebService的实现代码
Jun 19 Javascript
JS判断表单输入是否为空(示例代码)
Dec 23 Javascript
上传图片js判断图片尺寸和格式兼容IE
Sep 01 Javascript
png在IE6 下无法透明的解决方法汇总
May 21 Javascript
jquery实现滑屏大图定时收缩为小banner图片的广告代码
Sep 02 Javascript
vue,angular,avalon这三种MVVM框架优缺点
Apr 27 Javascript
微信小程序 检查接口状态实例详解
Jun 23 Javascript
详解React native全局变量的使用(跨组件的通信)
Sep 07 Javascript
详解Angular操作cookies方法
Jun 01 Javascript
js图数据结构处理 迪杰斯特拉算法代码实例
Sep 11 Javascript
jQuery-App输入框实现实时搜索
Nov 19 jQuery
TypeScript 学习笔记之基本类型
Jun 19 #Javascript
使用Chrome浏览器调试AngularJS应用的方法
Jun 18 #Javascript
使用AngularJS创建自定义的过滤器的方法
Jun 18 #Javascript
深入讲解AngularJS中的自定义指令的使用
Jun 18 #Javascript
3个可以改善用户体验的AngularJS指令介绍
Jun 18 #Javascript
在AngularJS应用中实现一些动画效果的代码
Jun 18 #Javascript
使用AngularJS对路由进行安全性处理的方法
Jun 18 #Javascript
You might like
PHP加速 eAccelerator配置和使用指南
2009/06/05 PHP
使用PHPCMS搭建wap手机网站
2015/09/20 PHP
javascript 图片上传预览-兼容标准
2009/06/01 Javascript
jQuery参数列表集合
2011/04/06 Javascript
js+数组实现网页上显示时间/星期几的实用方法
2013/01/18 Javascript
Internet Explorer 11 浏览器介绍:别叫我IE
2014/09/28 Javascript
简介JavaScript中substring()方法的使用
2015/06/06 Javascript
JavaScript模块化开发之SeaJS
2015/12/13 Javascript
jquery实现一个简单的表单验证实例
2016/03/30 Javascript
AngularJS Bootstrap详细介绍及实例代码
2016/07/28 Javascript
PHP获取当前页面完整URL的方法
2016/12/02 Javascript
jquery UI Datepicker时间控件冲突问题解决
2016/12/16 Javascript
详谈jQuery Ajax(load,post,get,ajax)的用法
2017/03/02 Javascript
vue使用watch 观察路由变化,重新获取内容
2017/03/08 Javascript
详解AngularJS controller调用factory
2017/05/19 Javascript
详解VueJS 数据驱动和依赖追踪分析
2017/07/26 Javascript
Node.js文件编码格式的转换的方法
2018/04/27 Javascript
vue2.0 element-ui中el-select选择器无法显示选中的内容(解决方法)
2018/08/24 Javascript
vue2中引用及使用 better-scroll的方法详解
2018/11/15 Javascript
利用layer实现表单完美验证的方法
2019/09/26 Javascript
vue多个元素的样式选择器问题
2019/11/29 Javascript
Node.js中console.log()输出彩色字体的方法示例
2019/12/01 Javascript
[01:07:19]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第一场 1月19日
2021/03/11 DOTA
pymssql数据库操作MSSQL2005实例分析
2015/05/25 Python
基于python绘制科赫雪花
2018/06/22 Python
Python使用pyodbc访问数据库操作方法详解
2018/07/05 Python
Python内存读写操作示例
2018/07/18 Python
使用urllib库的urlretrieve()方法下载网络文件到本地的方法
2018/12/19 Python
python求质数列表的例子
2019/11/24 Python
HTML5拖拽API经典实例详解
2018/04/20 HTML / CSS
2014年商场超市庆元旦活动方案
2014/02/14 职场文书
《放小鸟》教学反思
2014/04/20 职场文书
六一文艺汇演主持词
2015/06/30 职场文书
Python中的min及返回最小值索引的操作
2021/05/10 Python
sql中mod()函数取余数的用法
2021/05/29 SQL Server
教你使用VS Code的MySQL扩展管理数据库的方法
2022/01/22 MySQL