当使用扩展的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. MySQL学习笔记之数据类型

    数据类型在所有的数据库使用当中,都是避免不了的部分.以前每次写SQL语句,对于定义成哪种数据类型总是迷迷糊糊,今天就来彻底弄清.以下介绍仅针对MySQL 5.5以上版本. 一.字符串类型 1.char ...

  2. Mongodb基本数据类型、常用命令之增加、更新、删除

    1.null---表示空值或者该字段不存在,如{"name":null} 2.布尔 --- 和java中的布尔一样,有两种:true,false,如{"sex" ...

  3. ASP.NET MVC Razor

    Razor是MVC3中才有的新的视图引擎.我们知道,在ASP.NET中,ASPX的视图引擎依靠<%和%>来调用C#指令.而MVC3以后有了一套新的使用@标记的Razor语法,使用起来更灵活 ...

  4. mac xcode c++ cin cout注意细节一

    #include <iostream> using namespace std; 要同时存在 要不然std命名空间无法生效

  5. js获取URL地址栏中的参数

    function getUrlParam(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)( ...

  6. 10 Biggest Business Mistakes That Every Entrepreneur Should Avoid

    原文链接:http://www.huffingtonpost.com/syed-balkhi/10-biggest-business-mista_b_7626978.html When I start ...

  7. 浅谈Linux中的信号处理机制(二)

    首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...

  8. EF6 如何判断DataContext有修改,以及如何放弃修改

      如何判断DataContext有修改: EF6的 using (var db = new Model1()) { if (db.ChangeTracker.HasChanges()) { Cons ...

  9. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  10. Hibernate第一个例子

    我们先搭建这样的一个架构 里面包括实体类,实现类, 大配置, 小配置(映射文件), 以及架包 实体类我们就不重点介绍了 我们先把我们所需要用到的架包导入进来 我们先在src根目录下新建一个文件夹名为l ...