当使用扩展的JavaScript库或者插件API的时候,将需要使用声明文件(.d.ts)来描述库的类型。本文内容将包括如何编写声明文件相关的一些高级概念,然后用一些例子来展示如何将各式各样的概念与声明文件的描述相匹配。

流程

写.d.ts最好是从库的说明文档开始,而不是代码。从说明文档开始可以保证思维不受实现细节的影响,并且比阅读JS代码容易理解。下面的例子假设是根据说明文档写的,并且提供调用代码。

命名空间

当定义接口(例如"options"对象)的时候,你可以选择是否将这些类型放入一个模块中。这需要主观判断,如果.d.ts文件使用者更多的是用这些类型定义变量或者参数,并且类型的命名不会产生冲突,则将其放在全局命名空间较好。如果该类型不能够被直接引用,或者不能给一个唯一并且合理的命名,使用一个模块来防止与其他类型的冲突。

回调函数

很多JavaScript库都将函数作为参数,之后传入调用此函数时所用到的已知参数列表。在编写这些类型的函数签名时,不可以将这些参数标记为可选参数。正确的方式是想想"需要提供哪些参数?"(针对使用.d.ts的开发人员),而不是"哪些参数将被用到?"(针对函数被调用的时候)。

可扩展性和声明合并

当编写定义文件时,需要记住TypeScript的扩展现有对象的规则。可以选择使用匿名函数类型或者接口类型来声明一个变量:

声明一个匿名的类型:

declare var MyPoint: { x: number; y: number; };

声明一个接口类型:

interface SomePoint { x: number; y: number; }
declare var MyPoint: SomePoint;

从使用者角度来看,这些声明其实是一样的,但是SomePoint类型能够通过接口合并扩展:

interface SomePoint { z: number; }
MyPoint.z = 4; // OK

是否想让声明的变量可扩展是主观判断的。通常这也比较符合JavaScript库的目的。

类的分解

TypeScript中,类会创建两种单独的类型:实例类型,定义类的实例有哪些成员类型;构造函数类型,定义类的构造函数有哪些成员类型。构造函数的类型也被称为“静态部分”类型,因为它包含了类的静态成员。

虽然你可以使用关键字"typeof"来获取类的静态部分的类型,有时候使用类的分解模式来写定义文件是很有必要的,它可以明确的分离类的实例和静态类型。

标准模式:

class A {
static st: string;
inst: number;
constructor(m: any) {}
}

分解模式:

interface A_Static {
new(m: any): A_Instance;
st: string;
}
interface A_Instance {
inst: number;
}
declare var A: A_Static;

两种模式差异:

1.标准模式的类可以使用extends继承;分解模式不可以。这可能在TypeScript以后的版本中被改善,如果可以需要允许任意使用extends表达式。

2.都允许在后面添加静态部分的成员(通过合并声明)。

3.分解模式允许在后面添加实例部分的成员,而标准模式的不允许。

4.当使用分解模式的时候,需要为更多的类起一个合理的名称。

命名规则

一般来说,不需要给接口加上前缀I(如:IColor)。因为TypeScript中的接口比C#或Java里的接口具有更广泛的意义,加I的命名规则基本上没什么用。

案例

下面看例子吧。每个例子都已经提供了库的简单使用(这里需要自己对函数/对象进行脑补),然后就是定义精准类型的代码。如果有多个良好的声明方式,也会列出来。

选项对象(参数选项)

使用代码:

animalFactory.create("dog"); // 未通过验证: 如果给定options,必须提供name
animalFactory.create("giraffe", { name: "ronald" });
animalFactory.create("panda", { name: "bob", height: 400 });
animalFactory.create("cat", { height: 32 }); // 未通过验证: 如果给定options,必须提供name

类型声明:

module animalFactory {
interface AnimalOptions {
name: string;
height?: number;
weight?: number;
}
function create(name: string, animalOptions?: AnimalOptions): Animal;
}

带有属性的函数

使用代码:

zooKeeper.workSchedule = "morning";
zooKeeper(giraffeCage);

类型声明:

// 注意:函数必须处于模块之前
function zooKeeper(cage: AnimalCage);
module zooKeeper {
var workSchedule: string;
}

可使用关键字new也可直接调用的方法

使用代码:

var w = widget(32, 16);
var y = new widget("sprocket");
// w和y都是widgets
w.sprock();
y.sprock();

类型声明:

interface Widget {
sprock(): void;
} interface WidgetFactory {
new(name: string): Widget;
(width: number, height: number): Widget;
} declare var widget: WidgetFactory;

全局/封闭的库

使用代码:

// 可以这样写
import x = require('zoo');
x.open();
// 或者
zoo.open();

类型声明:

module zoo {
function open(): void;
} declare module "zoo" {
export = zoo;
}

外部模块中的单一复杂对象

// 可链式操作的eagles
import eagle = require('./eagle');
// 直接调用
eagle('bald').fly();
// 使用关键字"new"
var eddie = new eagle(1000);
// 设置属性
eagle.favorite = 'golden';

类型声明:

// 注意:在这里可以使用任何名称,但是整个文件中名称都要相同。
declare function eagle(name: string): eagle;
declare module eagle {
var favorite: string;
function fly(): void;
}
interface eagle {
new(awesomeness: number): eagle;
} export = eagle;
// 顺带加一点,node编译需要加--module,这个在TypeScript Modules(模块)中有提到,也给出了可运行的案例

回调函数

使用代码:

addLater(3, 4, (x) => console.log('x = ' + x));

类型声明:

// 注意:"void"返回类型在这里优先
function addLater(x: number, y: number, (sum: number) => void): void;

本篇基本脑补过来的... 后续如果工作中有使用到再记录详细的使用,之前一些列的TypeScript使用手册的随笔中,代码是经过修改成可运行的,还需要继续努力,不断改善自己,编写更高质量的代码。

TypeScript Writing .d.ts files(编写声明文件)的更多相关文章

  1. TypeScript学习笔记(八) - 声明文件

    本篇将介绍TypeScript的声明文件,并简单演示一下如何编写和使用声明文件.本篇也是这个系列的最后一篇. 一.声明文件简介 TypeScript作为JavaScript的超集,在开发过程中不可避免 ...

  2. TypeScript完全解读(26课时)_20.声明文件

    首先学习识别已有的js库的类型 识别已有的js库的类型 UMD既可以作为全局库使用,也可以作为模块使用 先在着手来编写一个全局的库 新建文件 接收一个title,改变页面title的值 这里用到 &a ...

  3. 如何编写 Typescript 声明文件

    使用TypeScript已经有了一段时间,这的确是一个好东西,虽说在使用的过程中也发现了一些bug,不过都是些小问题,所以整体体验还是很不错的. TypeScript之所以叫Type,和它的强类型是分 ...

  4. TypeScript声明文件

    为什么需要声明? 声明的本质是告知编译器一个标识符的类型信息.同时,在使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全.接口提示等功能. 声明在TypeScript中至关重要,只有通过 ...

  5. TypeScript 如何编写类库声明文件 .d.ts

    TypeScript 如何编写类库声明文件 .d.ts how to write a d.ts file declaration-files/ https://www.typescriptlang.o ...

  6. TypeScript 的声明文件的使用与编写

    https://fenying.net/2016/09/19/typings-for-typescript/ TypeScript 是 JavaScript 的超集,相比 JavaScript,其最关 ...

  7. JS如何捆绑TypeScript声明文件

    前话 TypeScript是JavaScript类型的超集 这是TypeScript的文档介绍的一句话,那么他们存在联系呢? 我的理解是,TypeScript在JavaScript基础上引入强类型语言 ...

  8. TS学习随笔(七)->声明文件

    now我们来看一看TS怎么声明文件, 在JS里面我们经常会使用各种第三方类库,引入方式也不太相同,常见的就是在HTML中通过script标签引入,然后就可以使用全局变量$或者jQuery了 我们通常这 ...

  9. TypeScript 之 声明文件的发布

    https://www.tslang.cn/docs/handbook/declaration-files/publishing.html 发布声明文件到npm,有两种方式: 与你的npm包捆绑在一起 ...

随机推荐

  1. 2015-SH项目总结

    2015年,加入现在的公司(外包公司,名字就不说了),做SH项目(化名),在这个月(2016.01)结束了. 虽然公司也有做项目总结,不过我还是自己也总结一次. 项目概况: 这是个为一间私人会所提供全 ...

  2. YourSQLDba版本升级总结

    在使用YourSQLDba做数据库备份.维护时,像其它软件一样,版本升级是不可避免的.因为YourSQLDba一直在不停更新版本.扩展功能.下面介绍一下升级YourSQLDba时的具体步骤和一些注意事 ...

  3. jni调试3(线程调试env变量问题)

    jni层调试线程死机原因 一,导致死机原因:   jni层中  线程函数中  只要添加调用env 的函数 ,,就会死机     二,解决方法 第一我们应该理解: ①(独立性) JNIEnv 是一个与线 ...

  4. RedHat6.2搭建FTP服务器

    我的环境: A:Red Hat Enterprise 6.2 IP:192.168.16.12 此机作测试端 B:Red Hat Enterprise 6.2 IP:192.168.16.13 此机做 ...

  5. Linux下5种IO模型的小结

    概述 接触网络编程,我们时常会与各种与IO相关的概念打交道:同步(Synchronous).异步(ASynchronous).阻塞(blocking)和非阻塞(non-blocking).关于概念的区 ...

  6. [HTML表格]在databases显示行的附加信息

    模板代码: <!-- DataTables CSS --> <link rel="stylesheet" href="{% static 'DataTa ...

  7. 按日子来干活——第一个Blog Day&Happy Day

    今天(周一)看到一位同仁的生活规划,感觉挺适合我,实践一下,就theo&tools day+code day+blog day,间歇性有happy day嘛~ blog day这样做,一篇bl ...

  8. Python+selenium自动化脚本编辑过程中遇到的问题和小技巧

    应该也不算是问题和技巧,算是实践中学习到的Python,记录下,也不定时更新 1.通过截取url判断 实例: self.assertEqual(self.broswer.current_url[sel ...

  9. 对象比较器:Comparable和Comparator

    在进行对象数组排序的过程中需要使用到比较器,比较器有两个:Comparable和Comparator ①.java.lang.Comparable:是在类定义是时候默认实现好的接口,里面提供有一个co ...

  10. Java8并发教程:Threads和Executors

    来之:ImportNew 欢迎阅读我的Java8并发教程的第一部分.这份指南将会以简单易懂的代码示例来教给你如何在Java8中进行并发编程.这是一系列教程中的第一部分.在接下来的15分钟,你将会学会如 ...