类型检查专注于解析值所具有的"形态",这是TypeScript的核心原则之一。这个有时候被称为"duck typing"或者"structural subtyping"。在TypeScript中,Interface中写入这些类型的命名规范,并且也是一种强有力的方式来对你的代码或者项目的外部代码进行约束。

实现第一个接口

要看看interface怎么工作的最简单的方式就是我们来写一个例子:

function printLabel(labelledObj: {label: string}) {
console.log(labelledObj.label);
}
var myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

类型检查器将会检查调用的"printLabel"。printLabel函数需要有一个对象作为参数,并且这个对象有"label"属性,该属性值类型是string。注意,我们的对象其实有比这个更多的属性,但编译器只检查当前匹配和需要的属性的类型。

我们再写一次上面的例子,只是这次我们使用interface来描述所需的"label"属性值是一个字符串:

interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
var myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

"LabelledValue"是一个名称,我们用它来描述前面那个例子中的需求。它依然体现出需要一个字符串类型的并且名为"label"的属性。注意,我们没有明确的说明在其他语言中也是在"printLabel"函数传入对象以实现此接口。这里,我们也仅仅是提下这个问题。如果我们传递给函数的对象符合要求,那么它就被允许了。

值的指出的是,类型检查不需求这些属性是来自挑选或者排序之后的,只需要interface所需的属性是存在的,并且类型也是相对应的即可。

属性可选

在interface中,并不是所有的属性都是必需的。有些可能是在某个条件下才需要,不是一直需要用到。当用户将一个对象传入到一个只具有一对属性的函数时(如创建一个"option bags"的方式),这些可选属性是很方便的。

这里有个这种方式的例子:

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"});

可选属性的interface和写普通的interface相似,只是每个可选属性用"?"符号标识,以作为申明这是可选的。

可选属性的有点是,你可以描述这些可能会用到的属性,同时还可以捕捉你明确了的那些不期望使用的属性。举例说明,我们为传入的"createSquare"输入了一个错误的属性名称,我们需要抛出一个错误信息来通知我们。

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.collor; // 类型检测器将会捕捉到你传入了错误的名称
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
var mySquare = createSquare({color: "black"});

函数类型

interface能够做和javascript的对象一样的事:描述形态的范围。除了描述一个对象的属性外,interface还可以描述函数类型。

用interface描述一个函数的类型,我们需要给interface一个调用标识。这就像一个只有参数列表和返回值类型的函数声明。

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

一旦定义后,我们就能和其他interface一样使用它了。在这里,我们将展示如何创建一个函数类型的变量并且将其赋值为相同类型的的函数值。

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;
}
}

函数参数一次只检查一个,相互检查每个位置对应参数的类型。在这里,我们的函数表达式的返回类型被它返回的值所表明(这里的false和true)。假如函数表达式返回的是number或者string,那么类型检查器将会通过返回类型与"SearchFunc" interface的描述类型不符用来警告我们。

数组类型

与我们使用interface来描述函数类型一样,我们也可以用interface来描述数组类型。数组类型有一个"index"类型用来描述了数组索引的类型,以及一个返回值类型用来表示相对应索引的元素类型。

interface StringArray {
[index: number]: string;
}
var myArray: StringArray;
myArray = ["Bob", "Fred"];

支持的两种索引类型:string和number。数组可以同时使用这两种索引类型。但也存在限制,数字索引的返回值类型必须是字符串索引返回值类型的子类型。

interface Something {
[index: string]: number;
[index: number]: number; //数字索引的返回值类型是number,它是字符串索引的返回值类型的子类型;若[index: string]:string,则数字索引的返回值类型也必须是string
}

虽然索引标识是个用来描述数组及"dictionary"模式的很好的方式,同时也迫使所有属性需要匹配他们的返回类型。在这个例子中,属性类型与索引类型不匹配,类型检查程序给出错误:

interface Dictionary {
[index: string]: string;
length: number; // 错误, 'length'的类型不是索引类型的子类型
}

类类型

实现接口

在C#和Java中,接口最基础的用法是用来强制让类去符合某种特定的规则,而在TypeScript中也可以这样做。

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

你也可以在接口中描述方法,然后在类中实现这个方法,就像我们下面例子中的"setTime":

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

接口描述了类的公有部分,而非公有和私有两部分。使用它们来检查一个类的实例的私有部分所含的特殊类型是行不通的。

类的静态部分和实例部分的差异

当处理类和接口的时候,你需要记住类有两种类型:静态的类型和实例的类型。你可能注意到了,如果你创建一个带有构造签名的接口并尝试创建一个用来实现这个接口的类的时候,会产生一个错误:

interface ClockInterface {
new (hour: number, minute: number);
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
// 错误信息: Class 'Clock' incorrectly implements interface 'ClockInterface'

这是因为当用一个类来实现一个接口时,只检查该类的实例部分。由于构造函数位于静态部分,它不包含在该检查中。

所以,我们需要直接来操作类的静态部分。在这个例子中,我们直接与该类进行操作:

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);

接口扩展

和类一样,接口也可以彼此间进行扩展。这个处理的任务是将一个接口的成员复制到另一个接口中,这样就可以更自由地把接口分离成可复用的组件。

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;

混合类型

正如我们之前所说,接口可以描述JavaScript世界里的丰富类型。因为JavaScript的动态的和灵活特性,你可能会偶尔碰到需要一个由上述多种类型组成的对象。

下面就有这么个例子,一个对象用来当做函数和对象一起使用,并且具有附加属性。

interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function counter():Counter{
var self = <Counter>function(start:number){
     self.interval = start;
console.log("Hello World " + start);
};
self.interval = 10;
self.reset = function(){
self.interval = 10;
}
return self;
}
var c = counter();//c.interval = 10
c(5); //c.interval = 5
c.interval = 15; //c.interval = 15
c.reset(); //c.interval = 10

与JavaScript的第三方库交互时,您可能需要使用上述模式来全面的定义类型。

TypeScript Interface(接口)的更多相关文章

  1. TypeScript之接口类型

    Interfaces 作为TypeScript中的核心特色之一,能够让类型检查帮助我们知道一个对象应该有什么,相比我们在编写JavaScript的时候经常遇到函数需要传递参数,可能在编写的时候知道这个 ...

  2. TypeScript入门五:TypeScript的接口

    TypeScript接口的基本使用 TypeScript函数类型接口 TypeScript可索引类型接口 TypeScript类类型接口 TypeScript接口与继承 一.TypeScript接口的 ...

  3. as3.0 interface接口使用方法

    [转]as3.0 interface接口使用方法 AS在2.0的时候就支持接口了 接口能够让你的程序更具扩展性和灵活性,打个例如 比方你定义了一个方法 代码: public function aMet ...

  4. interface接口

    当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口 interface. 定义接口使用的关键字不是class,是interface.接口中常见的成员: 这些成员都有 ...

  5. golang面向对象和interface接口

    一. golang面向对象介绍 1.golang也支持面向对象编程,但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言.2.golang没有类(class),golang语言的结合体(struc ...

  6. Golang 入门系列(四)如何理解interface接口

    前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友,可以先看看之前的文章.https://www.cnblogs.com/zhangweizhong/category ...

  7. go interface接口

    一:接口概要 接口是一种重要的类型,他是一组确定的方法集合. 一个接口变量可以存储任何实现了接口方法的具体值.一个重要的例子就是io.Reader和io.Writer type Reader inte ...

  8. java interface接口的传值方法

    A 类 package interface_test; public class A { private IPresenter ip; public A(IPresenter ip) { this.i ...

  9. JAVA 构造器, extends[继承], implements[实现], Interface[接口], reflect[反射], clone[克隆], final, static, abstrac

    记录一下: 构造器[构造函数]: 在java中如果用户编写类的时候没有提供构造函数,那么编译器会自动提供一个默认构造函数.它会把所有的实例字段设置为默认值:所有的数字变量初始化为0;所有的布尔变量设置 ...

随机推荐

  1. 极简Word排版示例(以Word2013为例)

    文档标题 第一行写下文档的名字,居中,微软雅黑字体,三号 章节标题 每一章的标题单独一行,光标选中这行,设置为标题1 每一节的标题单独一行,光标选中这行,设置为标题2 全部章节标题设置完毕后,下一步 ...

  2. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...

  3. [MCSM] Slice Sampler

    1. 引言 之前介绍的MCMC算法都具有一般性和通用性(这里指Metropolis-Hasting 算法),但也存在一些特殊的依赖于仿真分布特征的MCMC方法.在介绍这一类算法(指Gibbs samp ...

  4. java并发:线程同步机制之计数器&Exechanger

    第一节 CountDownLatch (1)初识CountDownLatch (2)详述CountDownLatch CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量. ...

  5. Google最新截屏案例详解

    Google从Android 5.0 开始,给出了截屏案例ScreenCapture,在同版本的examples的Media类别中可以找到.给需要开发手机或平板截屏应用的小伙伴提供了非常有意义的参考资 ...

  6. BI的相关问题[转]

    什么是BI? Business Intelligence(BI) = Data Warehouse(DW) + OLAP + Data Mining(DM) 商业智能=数据仓库+联机分析+数据挖掘 做 ...

  7. [HDU5903]Square Distance(DP)

    题意:给一个字符串t ,求与这个序列刚好有m个位置字符不同的由两个相同的串拼接起来的字符串 s,要求字典序最小的答案. 分析:按照贪心的想法,肯定在前面让字母尽量小,尽可能的填a,但问题是不知道前面填 ...

  8. MD5加密与验证

    package com.study; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException ...

  9. rar 命令

    1 wger http://www.rarlab.com/rar/rarlinux-3.9.2.tar.gz 下载文件包 会下载在当前目录 2 cp xxx.xxx ../ 复制xxx.xxx到上个目 ...

  10. 【Python】 [基础] 条件判断 与 循环 与dict和set

    # 条件判断 elif:  else if 的作用 注意: : [冒号]BMI =w/(h*h) if BMI<15:    print('较轻')elif BMI<25:    prin ...