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模拟多线程
Feb 07 Javascript
极酷的javascirpt,让你随意编辑任何网页
Feb 25 Javascript
js Dialog 实践分享
Oct 22 Javascript
js 本地预览的简单实现方法
Feb 18 Javascript
jquery实现动画菜单的左右滚动、渐变及图形背景滚动等效果
Aug 25 Javascript
浅谈JavaScript超时调用和间歇调用
Aug 30 Javascript
jQuery实现百叶窗焦点图动画效果代码分享(附源码下载)
Mar 14 Javascript
Google 地图叠加层实例讲解
Aug 06 Javascript
jQuery事件详解
Feb 23 Javascript
基于Jquery Ajax type的4种类型(详解)
Aug 02 jQuery
JavaScript中Object基础内部方法图
Feb 05 Javascript
详解vue实现坐标拾取器功能示例
Nov 18 Vue.js
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进行支付宝开发中return_url和notify_url的区别分析
2014/12/22 PHP
WordPress中获取页面链接和标题的相关PHP函数用法解析
2015/12/17 PHP
PHP Cookie学习笔记
2016/08/23 PHP
php版微信开发之接收消息,自动判断及回复相应消息的方法
2016/09/23 PHP
如何重写Laravel异常处理类详解
2020/12/20 PHP
javascript vvorld 在线加密破解方法
2008/11/13 Javascript
javascript 对表格的行和列都能加亮显示
2008/12/26 Javascript
Extjs 3.3切换tab隐藏相应工具栏出现空白解决
2013/04/02 Javascript
JavaScript中读取和保存文件实例
2014/05/08 Javascript
JS自动倒计时30秒后按钮才可用(两种场景)
2015/08/31 Javascript
用js实现每隔一秒刷新时间的实例(含年月日时分秒)
2017/10/25 Javascript
vue2.0 better-scroll 实现移动端滑动的示例代码
2018/01/25 Javascript
详解基于Wepy开发小程序插件(推荐)
2019/08/01 Javascript
JavaScript简单编程实例学习
2020/02/14 Javascript
[04:56]经典回顾:前Ehome 与 前LGD
2015/02/26 DOTA
[50:48]LGD vs CHAOS 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
[03:01]完美盛典趣味短片 DOTA2年度最佳&拉胯英雄
2019/12/07 DOTA
python操作CouchDB的方法
2014/10/08 Python
python 异常处理总结
2016/10/18 Python
Python socket网络编程TCP/IP服务器与客户端通信
2017/01/05 Python
pandas中Timestamp类用法详解
2017/12/11 Python
Python输出各行命令详解
2018/02/01 Python
python实现推箱子游戏
2020/03/25 Python
jupyter notebook 中输出pyecharts图实例
2020/04/23 Python
用Python做一个久坐提醒小助手的示例代码
2020/02/10 Python
Python 读取xml数据,cv2裁剪图片实例
2020/03/10 Python
从零开始的TensorFlow+VScode开发环境搭建的步骤(图文)
2020/08/31 Python
Ray-Ban雷朋美国官网:全球领先的太阳眼镜品牌
2016/07/20 全球购物
蒙蒂塞罗商店:Monticello Shop
2018/11/25 全球购物
六查六看自查材料
2014/02/17 职场文书
公司授权委托书格式样本
2014/10/01 职场文书
机动车交通事故协议书
2015/01/29 职场文书
Java8中接口的新特性使用指南
2021/11/01 Java/Android
HTML CSS 一个标签实现带动画的抖音LOGO
2022/04/26 HTML / CSS
Springboot-cli 开发脚手架,权限认证,附demo演示
2022/04/28 Java/Android
mysql如何查询连续记录
2022/05/11 MySQL