类型检查专注于解析值所具有的"形态",这是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. 安装包制作工具 SetupFactory使用1 详解

    2014-11-19 Setup Factory 是一个强大的安装程序制作工具.提供了安装制作向导界面,即使你对安装制作不了解,也可以生成专业性质的安装程序.可建立快捷方式,也可直接在 Windows ...

  2. Middleware的艺术

    定义 Middleware直译叫中间件,目前在百度上很难找到一个简单明了的含义解释,.Net下以前也比较难以看到它的身影,但在Microsoft.Owin里,多个地方都看到MiddleWare,我近来 ...

  3. MATLAB中plot()画图的颜色线型和希腊字母参数设置

    y         黄色           ·             点线      m         粉红           ○             圈线      c          ...

  4. JS 问题集锦

    [1]js页面跳转 和 js打开新窗口方法 第一种: <script language="javascript" type="text/javascript&quo ...

  5. 【Javascript】好用的js弹层插件,layerUI

    官网:layerUI 中文手册:layerAPI

  6. C# 反射范范的理解下

    程序进行时引入程序集.动态的调用方法属性事件. Assembly类. type类.

  7. iOS 隐藏/去掉 导航栏返回按钮中的文字

    [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(, -) forBarMetrics:U ...

  8. git 格式化输出版本信息

    git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&l ...

  9. 【BZOJ 3053】The Closest M Points

    KDTree模板,在m维空间中找最近的k个点,用的是欧几里德距离. 理解了好久,昨晚始终不明白那些“估价函数”,后来才知道分情况讨论,≤k还是=k,在当前这一维度距离过线还是不过线,过线则要继续搜索另 ...

  10. java基础语法要点<一>(基于1.8)

    http://yishouce.com/java/run http://www.shucunwang.com/RunCode/java/ 数据类型 8种基本数据类型及对应的 类型封装器 byte, s ...