TypeScript 的两种声明文件写法的区别和根本意义

Easter79
• 阅读 523

作者: Angus.Fenying <i.am.x.fenying@gmail.com>

日期: 2016-09-15 05:40 PM

我们知道 NPM 包可以有内建的 TS 声明文件,从而免去使用 typings 工具安装 TS 声明文件的操作。那既然可以有内建的声明文件,为何还需要额外安装呢?因为不是 所有人都在使用 TypeScript,很多 NPM 模块都是纯 JavaScript 编写的,其作者 没有太大的可能性为之编写模块声明文件。而且内建的声明文件有一定约束。

TypeScript 的 DefinitelyTyped 声明文件有两种写法,一种叫做 **全局类型声明(Global Type Definition)**,另一个则是叫做 **模块导出声明(External Module Definition)**。

External Module 一词源自 TypeScript 1.5 之前的 内部模块/外部模块 之说,而 1.5 之后内部模块变成了 namespace,外部模块直接化为模块, 不再有内外部模块之说。

所以这里将 External Module Definition 译为 模块导出声明 比较合适。

DefinitelyTyped 对此的说明是:

  • 如果你的模块需要将新的名称引入全局命名空间,那么就应该使用全局声明。
  • 如果你的模块无需将新的名称引入全局命名空间,那么就应该使用模块导出声明。

这两者有什么不同呢?

首先,最主要的区别在于,NPM 模块里面的内建声明文件必须使用模块导出声明写法, 否则 TypeScript 编译无法通过。下面来看一个简单的例子:

以一个名为 abc 的模块为例,TS源代码如下:

export function abc(s: string): string {

    return s.substr(0, 4);
}

其声明文件有两种写法:

  • 第一种,模块导出声明写法

    declare interface funcAbcSign {
        (s: string): string
    }
    
    export declare let abc: funcAbcSign;
    
  • 第二种,全局类型声明写法

    declare module "abc" {
        interface funcAbcSign {
            (s: string): string
        }
    
        export let abc: funcAbcSign;
    }
    

如果要理解两者的区别,首先要理解其意义。模块导出声明写法 中,单从这个文件内容 看来是无法得知这些内容属于哪个模块的。所以必须将之与模块放在一起,作为内建声明文件, TypeScript 编译器才能得知其所属的模块。(或者放进 typings 的 external 目录)

全局类型声明写法 中,实际上是将模块名称 abc 引入了全局空间,即告诉 TypeScript 编译器,存在一个叫 abc 的模块,想使用里面的名称,就 import 吧!

因为任何一个 Node.js 的模块都是必须依靠 require 加载的才能通过字段引用的方式 使用里面的名称,即是说 一个模块无法真正地将任何名称引入全局的命名空间中,所以不应该也不能在一个模块 的内建声明文件里使用全局声明写法!

这样,就明白了什么时候应该使用全局声明写法,什么时候应该使用模块导出声明写法了

如果你写的 TypeScript 文件是在浏览器上通过 <script> 标签加载的,那么里面的 变量、函数等都会被引入到全局命名空间中,这时候就需要为这个文件写一份全局类型声明 了!比如这个文件:

// 定义了一个全局变量,整个页面内都可见
let appStartedTime: Date = new Date();

你需要为之写一份 .d.ts 文件,供其它 ts 文件引用:

// 这里将变量名 appStartedTime 引入了 TypeScript 的全局命名空间中。
declare let appStartedTime: Date;

除此之外,你可以用一个全局类型声明文件定义多个模块、命名空间,例如:

// node.d.ts

declare namespace NodeJS {

    export interface Error {

        "name": string;
    }
}

declare module "http" {

    // Node built-in module http
}

declare module "fs" {

    // Node built-in module fs
}

或者深层模块声明:

declare module "sample/lib1" {

    export let name: number;
}

declare module "sample/lib2" {

    export let value: number;
}

declare module "sample" {

    export * from "sample/lib1";

    export * from "sample/lib2";
}

这是模块导出声明写法做不到的。

综上所述,最直观的解释是:

  • 全局类型声明里的名称将被引入整个 TypeScript 全局命名空间中,从引用这个 声明文件起就可以自由使用。
  • 模块导出声明里的名称必须通过 import/require 才能使用。
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
TypeScript 的声明文件的使用与编写
作者:Angus.Fenying<i.am.x.fenying@gmail.com(https://www.oschina.net/action/GoToLink?urlmailto%3Ai.am.x.fenying%40gmail.com)\日期:2016091909:53PM1\.什么是声明文件?
Stella981 Stella981
3年前
OpenSSL 之 RSA 相关命令学习笔记
作者:Angus.Fenying<i.am.x.fenying@gmail.com(https://www.oschina.net/action/GoToLink?urlmailto%3Ai.am.x.fenying%40gmail.com)\日期:2016111010:35PM本文介绍OpenSSL命令行进
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k