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 相关文章推荐
ExtJS GTGrid 简单用户管理
Jul 01 Javascript
JS俄罗斯方块,包含完整的设计理念
Dec 11 Javascript
js验证输入是否为手机号码或电话号码示例
Dec 30 Javascript
jquery实现在页面加载的时自动为日期插件添加当前日期
Aug 20 Javascript
jQuery+CSS实现一个侧滑导航菜单代码
May 09 Javascript
第一次接触Bootstrap框架
Oct 24 Javascript
深入理解JavaScript创建对象的多种方式以及优缺点
Jun 01 Javascript
封装运动框架实战左右与上下滑动的焦点轮播图(实例)
Oct 17 Javascript
vue组件之间通信方式实例总结【8种方式】
Feb 22 Javascript
Vue解析带html标签的字符串为dom的实例
Nov 13 Javascript
JS中的const命令你真懂它吗
Mar 08 Javascript
vue渲染方式render和template的区别
Jun 05 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
Email+URL的判断和自动转换函数
2006/10/09 PHP
php遍历类中包含的所有元素的方法
2015/05/12 PHP
php中switch语句用法详解
2015/08/17 PHP
js使浏览器窗口最大化实现代码(适用于IE)
2013/08/07 Javascript
JS 如何获取radio选中后的值及不选择取radio的值
2013/10/28 Javascript
jQuery动态显示和隐藏datagrid中的某一列的方法
2013/12/11 Javascript
input输入框鼠标焦点提示信息
2015/03/17 Javascript
关于JS 预解释的相关理解
2016/06/28 Javascript
前端自动化开发之Node.js的环境搭建教程
2017/04/01 Javascript
使用npm安装最新版本nodejs
2018/01/18 NodeJs
详解react-redux插件入门
2018/04/19 Javascript
javascript标准库(js的标准内置对象)总结
2018/05/26 Javascript
Bootstrap开发中Tab标签页切换图表显示问题的解决方法
2018/07/13 Javascript
使用Vuex解决Vue中的身份验证问题
2018/09/28 Javascript
vue.js实现图书管理功能
2019/09/24 Javascript
详细介绍解决vue和jsp结合的方法
2020/02/06 Javascript
不刷新网页就能链接新的js文件方法总结
2020/03/01 Javascript
在vue中使用echarts(折线图的demo,markline用法)
2020/07/20 Javascript
python实现搜索指定目录下文件及文件内搜索指定关键词的方法
2015/06/28 Python
Python算法应用实战之栈详解
2017/02/04 Python
Python 专题一 函数的基础知识
2017/03/16 Python
Python 操作文件的基本方法总结
2017/08/10 Python
pycharm下打开、执行并调试scrapy爬虫程序的方法
2017/11/29 Python
tensorflow学习教程之文本分类详析
2018/08/07 Python
对Python中Iterator和Iterable的区别详解
2018/10/18 Python
 Alo Yoga官网:购买瑜伽服装
2018/06/17 全球购物
Europcar意大利:汽车租赁
2019/07/07 全球购物
美国知名的隐形眼镜电商:Contacts America
2019/11/19 全球购物
公司总经理岗位职责
2014/03/15 职场文书
超市仓管员岗位职责
2014/04/07 职场文书
小学阳光体育活动总结
2014/07/05 职场文书
中小学校园安全广播稿
2014/09/29 职场文书
党员反邪教心得体会
2016/01/15 职场文书
Spring Boot 实现敏感词及特殊字符过滤处理
2021/06/29 Java/Android
vue elementUI批量上传文件
2022/04/26 Vue.js
CSS实现背景图片全屏铺满自适应的3种方式
2022/07/07 HTML / CSS