类型检查专注于解析值所具有的"形态",这是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. HomeKit 与老旧设备

    苹果推了HomeKit,已经有很多厂商在做,可以达到Siri控制所有设备的功能. 但是Siri也不是万能的,对人类的语义理解也会产生差错,不过我相信未来这个问题会解决掉.     如果家里有老旧的电视 ...

  2. 快速备份和还原 MySQL 数据库的另一种方法

    一直使用 SQL Server 作为公司产品的数据库来存储系统数据,所以备份还原一直都不是问题,因为 SQL Server 的备份还原非常迅速和易用.但今年公司改变策略,使用起 MySQL 数据库作为 ...

  3. 283 Move Zeroes

    /** * 题意:将0挪到末尾,并且不改数组中原有元素的顺序 * 解析:找到0元素,然后寻找其后面非0的元素,进行交换位置 * @param {number[]} nums * @return {vo ...

  4. sql 几点记录

      1       With子句 1.1     学习目标 掌握with子句用法,并且了解with子句能够提高查询效率的原因. 1.2     With子句要点 with子句的返回结果存到用户的临时表 ...

  5. Common Issues Which Cause Roles to Recycle

    This section lists some of the common causes of deployment problems, and offers troubleshooting tips ...

  6. P值,“差异具有显著性”和“具有显著差异”

      P值是论文中最常用的一个统计学指标,可是其误用.解释错误的现象却很常见.因此,很有必要说明p值的意义.用法及常见错误.   P值指的是比较的两者的差别是由机遇所致的可能性大小.P值越小,越有理由认 ...

  7. 数据库MongoDB查询语句--持续更新

    模糊查询: 包含字符串str : find({'name':/str/i}); {'name':/str/} 以str开头:   {'name':/^str/} $in查询: 字段:{ field: ...

  8. virtio 半虚拟化驱动

    半虚拟化驱动 5.1.1 virtio概述 KVM是必须使用硬件虚拟化辅助技术(如Intel VT-x.AMD-V)的hypervisor,在CPU运行效率方面有硬件支持,其效率是比较高的:在有Int ...

  9. MyBatis中的resultType和resultMap

    MyBatis的查询在进行映射的时候,返回值类型可以使用resultType同时也可以使用resultMap.前者表示直接的返回值类型,一般是domain名称,当然这里可以写domain的全部路径也可 ...

  10. python 中的sort 和java中的Collections.sort()函数的使用

    x=[1,2,3] x.sort()对的,x这个都变了 y=x.sort()错误 y=sorted(x)对的,x拍好序的一个副本 python中用匿名函数和自定义函数排序:(很奇怪的是比较函数返回的是 ...