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 相关文章推荐
javascript自适应宽度的瀑布流实现思路
Feb 20 Javascript
jQuery学习笔记(4)--Jquery中获取table中某列值的具体思路
Apr 10 Javascript
JQuery获取样式中的background-color颜色值的问题
Aug 20 Javascript
将两个div左右并列显示并实现点击标题切换内容
Oct 22 Javascript
js每隔5分钟执行一次ajax请求的实现方法
Nov 27 Javascript
深入理解javascript作用域和闭包
Sep 23 Javascript
浅谈javascript语法和定时函数
May 03 Javascript
opencv 识别微信登录验证滑动块位置
Aug 07 Javascript
vue之组件内监控$store中定义变量的变化详解
Nov 08 Javascript
微信小程序实现页面浮动导航
Jan 08 Javascript
JavaScript实现Tab标签页切换的最简便方式(4种)
Jun 28 Javascript
vue+elementUI 实现内容区域高度自适应的示例
Sep 26 Javascript
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开发留言板的CRUD(增,删,改,查)操作
2012/04/19 PHP
实用的简单PHP分页集合包括使用方法
2013/10/21 PHP
Yii2设置默认控制器的两种方法
2017/05/19 PHP
thinkPHP中钩子的使用方法实例分析
2017/11/16 PHP
Javascript中的常见排序算法
2007/03/27 Javascript
js读取被点击次数的简单实例(从数据库中读取)
2014/03/07 Javascript
js实现鼠标滑过文字链接色彩变化的效果
2015/05/06 Javascript
javascript实现一个数值加法函数
2015/06/26 Javascript
DeviceOne 让你一见钟情的App快速开发平台
2016/02/17 Javascript
使用smartupload组件实现jsp+jdbc上传下载文件实例解析
2017/01/05 Javascript
js实现做通讯录的索引滑动显示效果和滑动显示锚点效果
2017/02/18 Javascript
BootStrap daterangepicker 双日历控件
2017/06/02 Javascript
node.js基于fs模块对系统文件及目录进行读写操作的方法详解
2017/11/10 Javascript
Vue 路由切换时页面内容没有重新加载的解决方法
2018/09/01 Javascript
JS实现简单省市二级联动
2019/11/27 Javascript
Vant+postcss-pxtorem 实现浏览器适配功能
2021/02/05 Javascript
python利用装饰器进行运算的实例分析
2015/08/04 Python
Python生成密码库功能示例
2017/05/23 Python
Python判断中文字符串是否相等的实例
2018/07/06 Python
python 实现视频流下载保存MP4的方法
2019/01/09 Python
django将数组传递给前台模板的方法
2019/08/06 Python
Python时间序列缺失值的处理方法(日期缺失填充)
2019/08/11 Python
使用Python调取任意数字资产钱包余额功能
2019/08/15 Python
tensorflow中tf.slice和tf.gather切片函数的使用
2020/01/19 Python
基于python3生成标签云代码解析
2020/02/18 Python
Python如何执行系统命令
2020/09/23 Python
英国最大的汽车交易网站:Auto Trader UK
2016/09/23 全球购物
基本款天堂:Everlane
2017/05/13 全球购物
马来西亚最大的电器网站:Senheng
2017/10/13 全球购物
英国珠宝网站Argento: PANDORA、Olivia Burton和Nomination等
2020/05/08 全球购物
C#和SQL Server的面试题
2016/08/12 面试题
在校生党员自我评价
2013/09/25 职场文书
学校岗位设置方案
2014/01/16 职场文书
担保书范文
2019/07/09 职场文书
python中的plt.cm.Paired用法说明
2021/05/31 Python
JS轻量级函数式编程实现XDM三
2022/06/16 Javascript