当使用扩展的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. vim linux下查找显示^M并且删除

    linux下 ^M的输入方法是ctrl+v然后再ctrl+m vim下在文件中显示^M:e ++ff=unix % 在文件中删除^M:%s/^M$//g 在linux下查找^Mfind ./ | xa ...

  2. Windows下使用Xshell建立反向隧道

    反向隧道是一个进行内网穿透的简单而有用的方法.在Linux下通过OpenSSH和AutoSSH可以很容易地建立稳定的反向隧道.但是在Windows下,还能看到有人特意装个Cygwin来运行这些工具…… ...

  3. [转]PaaS平台分类

    本文转自阿朱说 大家发现没,自从我们上升到有规模的互联网架构后,咱们中国的技能能力就跟不上了,只能采取国际业界顶级大公司开源出来的而且已经经受住大规模实际应用考验的组件来搭架构,因而咱们近几年大规模网 ...

  4. 分布式搜索引擎Elasticsearch的查询与过滤

    一.写入 先来一个简单的官方例子,插入的参数为-XPUT,插入一条记录. curl -XPUT 'http://localhost:9200/test/users/1' -d '{ "use ...

  5. 交互式makefile

    之前一直不知道在shell中调用read赋值后,怎么传给makefile中的变量,后来才恍然大悟. myname := $(shell read -p "Enter your name:&q ...

  6. 服务器运行环境(LNMP)安装说明

    服务器运行环境(LNMP)安装说明 因为公司需要一套流程标准,所以写了如下步骤. 先下载文件environment.tar,将文件上传到服务器. 使用命令解压文件,tar xvf environmen ...

  7. Fragment 与Activity

    一个Activity 对应 多个Fragment; 每一个类 extends Fragment , 一个Activity 可以同时显示多个 Fragment; Fragment是依赖于Activity ...

  8. 4412开发板搭建Uboot、Kernel和Android4.0的编译环境方法

    本文转自迅为4412开发板实战教程书籍:http://www.topeetboard.com 迅为是基于Ubuntu12.04.2平台做开发,所有的配置和编译脚本也是基于此平台,没有在其它平台上测试过 ...

  9. NopCommerce 增加 Customer Settings

    预期: 仿照Customer 的 Phone number enabled 和 required 增加MemberType 相关步骤如下: 1.运行站点 Admin -> Settings -& ...

  10. UVA&&POJ离散概率与数学期望入门练习[4]

    POJ3869 Headshot 题意:给出左轮手枪的子弹序列,打了一枪没子弹,要使下一枪也没子弹概率最大应该rotate还是shoot 条件概率,|00|/(|00|+|01|)和|0|/n谁大的问 ...