【TypeScript】TypeScript 学习 2——接口
在 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;
这样就使用到三种类型了,分别是方法(接口自己是个方法)、属性、方法(定义了方法成员)。
【TypeScript】TypeScript 学习 2——接口的更多相关文章
- typescript handbook 学习笔记4
概述 这是我学习typescript的笔记.写这个笔记的原因主要有2个,一个是熟悉相关的写法:另一个是理清其中一些晦涩的东西.供以后开发时参考,相信对其他人也有用. 学习typescript建议直接看 ...
- typescript handbook 学习笔记3
概述 这是我学习typescript的笔记.写这个笔记的原因主要有2个,一个是熟悉相关的写法:另一个是理清其中一些晦涩的东西.供以后开发时参考,相信对其他人也有用. 学习typescript建议直接看 ...
- TypeScript 真香系列——接口篇
接口带来了什么好处 好处One —— 过去我们写 JavaScript JavaScript 中定义一个函数,用来获取一个用户的姓名和年龄的字符串: const getUserInfo = funct ...
- TypeScript之路----探索接口(interface)的奥秘
TypeScript定义接口 要想掌握typescript的知识,接口是其必经之路.很多东西都需要接触到接口,接口除了对类的一部分行为进行抽象以外,也常用于对对象的形状进行描述.接下来我们就一起来学习 ...
- typescript handbook 学习笔记2
概述 这是我学习typescript的笔记.写这个笔记的原因主要有2个,一个是熟悉相关的写法:另一个是理清其中一些晦涩的东西.供以后开发时参考,相信对其他人也有用. 学习typescript建议直接看 ...
- 使用Typescript重构axios(十一)——接口扩展
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- [TypeScript] TypeScript对象转JSON字符串范例
[TypeScript] TypeScript对象转JSON字符串范例 Playground http://tinyurl.com/njbrnrv Samples class DataTable { ...
- 学习java接口知识
学习java接口知识 //一个类最多只能有一个直接的父类.但是有多个间接的父类. java是单继承. class ye_01{ String name; } class fu_01 extends y ...
- OpenCV学习C++接口 Mat像素遍历详解
OpenCV学习C++接口 Mat像素遍历详解
- C# 你什么让程序员寂寞成酱紫 (男生版 娱乐中学习 抽象类 接口 继承 实现方法 )
你什么让程序员寂寞成酱紫 (男生版 娱乐中学习 抽象类 接口 继承 实现方法 ) 一个家庭 相当于 一个空间,这个空间里 有 很多元素,比如 爱,爱这个抽象事物,可能有很多动作,接吻.交流,对于一 ...
随机推荐
- 大型运输行业实战_day04_3_高级查询+分页
1.高级查询+分页最终结果 2.分页的本质分析 前端传入:当前页 和 每页显示条数 数据库必须查询出:数据列表 和 总共条数 页面显示包括的数据有: 列表 + 每页显示条数 + 当前页 + 总共 ...
- 关于时间查询的sql语句
今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ...
- 在winsshd 中添加id_rsa.pub 实现Windows 服务器主机自动信任Linux 客户端
文章一. 生成密钥: 在Linux主机(ssh客户端),通过ssh-keygen在建立SSH keys# ssh-keygen -t rsa (连续三次回车,即在本地生成了公钥和私钥,不设置密码)将在 ...
- MAVEN 引入外部JAR 包
MAVEN引入AXIS依赖的JAR包 在POM.XML中加入即可 <!-- axis 1.4 jar start --> <dependency> <groupId> ...
- 记一次spring-session登录后失效的问题
用户登录后,可以进入页面,但ajax请求或跳转其他页面时,会被当做匿名用户,即没有登录.查看session数据库,发现多出两条session,一条为正常数据,里面有对应的用户名:另一条为异常的数据,没 ...
- np.eye()
今天在完成深度学习的相关编程作业的时候,发现代码中出现了一个关于np.eye()的函数,这个函数的用法非常的简单,但是在预制的代码中,这个函数的用法并非单单制造一个对角矩阵,而是通过其来将一个labe ...
- X_PU
通俗易懂告诉你CPU/GPU/TPU/NPU...XPU都是些什么鬼?[附把妹秘籍] 2017-10-27 19:54移动芯片/谷歌 作者:iot101君 物联网智库 原创 转载请注明来源和出处 现在 ...
- java非常好用的读取文件的流的代码
学过java的都知道java中有非常多的读取文件流的操作.这个要回到javase的io操作了.io流说实话,初学者学的肯定会非常混乱,那么多流,什么输入流,输出流,什么文件流,什么字节流,等等.我在这 ...
- 【校招面试 之 C/C++】第29题 C/C++ 关键字extern
1.extern "C" extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码.加上extern "C"后,会指示 ...
- SweetAlert2 弹窗
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...