Typescript声明文件写法
Typescript的声明文件是一个.d.ts为后缀的Typescript代码文件,作用是描述一个Javascript模块内所有导出接口的类型信息。
Typescript的DefinitelyTyped 声明文件有两种写法:
- 全局类型声明(Global Type Definition)
- 模块导出声明(External Module Definition)
两种声明区别及意义
我们知道npm包有内建的TS声明文件,从而免去使用typings工具安装TS声明文件的操作。
- 既然可以有内建声明文件,为何还需额外安装呢?
因为不是所有人都在使用Typescript,很多npm包都是纯Javascript编写,作者没太大可能性为其编写模块声明文件,而且内建的声明文件有一定约束。
- 什么时候使用全局类型声明?什么时候使用导出类型声明?
- 需要将新名称引入全局命名空间,就使用全局声明
- 无需将新名称引入全局命名空间,就使用模块导出声明
- 两者有什么区别?
主要区别在于,npm包里面的内建声明必须使用模块导出声明写法,否则Typescript编译无法通过。
举例说明
export function abc(s: string): string {
return s.substr(0, 4);
}
其声明文件写法:
- 模块导出声明写法
declare interface Iabc {
(s: string): string
}
export declare let abc: Iabc;
- 全局类型声明写法
declare module "Iabc" {
iterface abc {
(s: string): string
}
export let abc: Iabc;
}
模块导出声明写法中,单从文件内容看,无法得知这些内容属于哪个模块,所以必须将之与模块放在一起,作为内建声明文件,Typescript编辑才能得知其所属模块(或放进typings的external目录)。
全局类型声明写法中,实际是将模块Iabc
引入全局空间,即告诉Typescript编辑器,存在一个叫Iabc
的模块,想使用就import吧!
因为任何一个 Node.js 的模块都是必须依靠 require 加载的才能通过字段引用的方式 使用里面的名称,即
一个模块无法真正地将任何名称引入全局的命名空间中,所以不应该也不能在一个模块的内建声明文件里使用全局声明写法
如果你的Typescript文件是通过<scipt>
标签加载,那么变量、函数等都会被引入到全局命名空间中,这时就要为这个文件写一份全局类型声明了。
例如:
// 定义一个全局变量,整个页面都可见
let startTime: Date = new Date();
需要为之写一份.d.ts
文件,供其ts文件引用:
// 这里将变量名 startTime 引入了 TypeScript 的全局命名空间中。
declare let startTime: 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 才能使用。
网友评论