當(dāng)使用第三方庫(kù)時(shí),我們需要引用它的聲明文件氛什,才能獲得對(duì)應(yīng)的代碼補(bǔ)全七芭、接口提示等功能。
-
declare var
聲明全局變量 -
declare function
聲明全局方法 -
declare class
聲明全局類 -
declare enum
聲明全局枚舉類型 -
declare namespace
聲明(含有子屬性的)全局對(duì)象 -
interface
和type
聲明全局類型 -
export
導(dǎo)出變量 -
export namespace
導(dǎo)出(含有子屬性的)對(duì)象 -
export default
ES6 默認(rèn)導(dǎo)出 -
export =
commonjs 導(dǎo)出模塊 -
export as namespace
UMD 庫(kù)聲明全局變量 -
declare global
擴(kuò)展全局變量 -
declare module
擴(kuò)展模塊 -
/// <reference />
三斜線指令
通常我們會(huì)把聲明語(yǔ)句放到一個(gè)單獨(dú)的文件(jQuery.d.ts
)中照卦,這就是聲明文件
聲明文件必需以 .d.ts 為后綴式矫。
全局變量這種模式的聲明文件
// src/jQuery.d.ts
declare var jQuery: (selector: string) => any;
將jQuery.d.ts
放在項(xiàng)目目錄中,可檢查tsconfig.json
中的 files
役耕、include
和 exclude
配置采转,確保其包含了jQuery.d.ts
文件
第三方聲明文件
使用 @types 統(tǒng)一管理第三方庫(kù)的聲明文件
npm install @types/jquery --save-dev
書寫聲明文件
當(dāng)一個(gè)第三方庫(kù)沒有提供聲明文件時(shí),我們就需要自己書寫聲明文件了。前面只介紹了最簡(jiǎn)單的聲明文件內(nèi)容故慈,而真正書寫一個(gè)聲明文件并不是一件簡(jiǎn)單的事板熊,以下會(huì)詳細(xì)介紹如何書寫聲明文件。
全局變量
如jQuery
declare var
聲明全局變量
declare let jQuery: (selector: string) => any;
declare const jQuery: (selector: string) => any;
declare function
聲明全局變量
declare function jQuery(selector: string): any;
declare class
declare class Animal {
name: string;
constructor(name: string);
sayHi(): string;
}
declare enum
declare enum Directions {
Up,
Down,
Left,
Right
}
declare namespace
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
}
嵌套的命名空間
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
namespace fn {
function extend(object: any): void;
}
}
interface
和 type
interface AjaxSettings {
method?: 'GET' | 'POST'
data?: any;
}
declare namespace jQuery {
function ajax(url: string, settings?: AjaxSettings): void;
}
為防止全局變量污染察绷,最好是放在namespace
下
declare namespace jQuery {
interface AjaxSettings {
method?: 'GET' | 'POST'
data?: any;
}
function ajax(url: string, settings?: AjaxSettings): void;
}
// 使用
let settings: jQuery.AjaxSettings = {
method: 'POST',
data: {
name: 'foo'
}
};
jQuery.ajax('/api/post_something', settings);
npm包
npm 包的聲明文件可能存在于兩個(gè)地方:
- 與該 npm 包綁定在一起干签。判斷依據(jù)是 package.json 中有 types 字段,或者有一個(gè) index.d.ts 聲明文件拆撼。這種模式不需要額外安裝其他包容劳,是最為推薦的,所以以后我們自己創(chuàng)建 npm 包的時(shí)候闸度,最好也將聲明文件與 npm 包綁定在一起竭贩。
- 發(fā)布到 @types 里。我們只需要嘗試安裝一下對(duì)應(yīng)的 @types 包就知道是否存在該聲明文件筋岛,安裝命令是 npm install @types/foo --save-dev娶视。這種模式一般是由于 npm 包的維護(hù)者沒有提供聲明文件,所以只能由其他人將聲明文件發(fā)布到 @types 里了睁宰。
假如以上兩種方式都沒有找到對(duì)應(yīng)的聲明文件肪获,那么我們就需要自己為它寫聲明文件了。由于是通過 import 語(yǔ)句導(dǎo)入的模塊柒傻,所以聲明文件存放的位置也有所約束孝赫,一般有兩種方案:
- 創(chuàng)建一個(gè) node_modules/@types/foo/index.d.ts 文件,存放 foo 模塊的聲明文件红符。這種方式不需要額外的配置青柄,但是 node_modules 目錄不穩(wěn)定,代碼也沒有被保存到倉(cāng)庫(kù)中预侯,無(wú)法回溯版本致开,有不小心被刪除的風(fēng)險(xiǎn),故不太建議用這種方案萎馅,一般只用作臨時(shí)測(cè)試双戳。
- 創(chuàng)建一個(gè) types 目錄,專門用來(lái)管理自己寫的聲明文件糜芳,將 foo 的聲明文件放到 types/foo/index.d.ts 中飒货。這種方式需要配置下 tsconfig.json 中的 paths 和 baseUrl 字段。
export
npm 包的聲明文件與全局變量的聲明文件有很大區(qū)別峭竣。在 npm 包的聲明文件中塘辅,使用 declare
不再會(huì)聲明一個(gè)全局變量,而只會(huì)在當(dāng)前文件中聲明一個(gè)局部變量皆撩。只有在聲明文件中使用export
導(dǎo)出扣墩,然后在使用方import
導(dǎo)入后,才會(huì)應(yīng)用到這些類型聲明。
混用 declare
和export
// types/foo/index.d.ts
declare const name: string;
declare function getName(): string;
declare class Animal {
constructor(name: string);
sayHi(): string;
}
declare enum Directions {
Up,
Down,
Left,
Right
}
interface Options {
data: any;
}
export { name, getName, Animal, Directions, Options };
注意沮榜,與全局變量的聲明文件類似盘榨,interface 前是不需要 declare 的。
export namespace
// types/foo/index.d.ts
export namespace foo {
const name: string;
namespace bar {
function baz(): string;
}
}
// src/index.ts
import { foo } from 'foo';
console.log(foo.name);
foo.bar.baz();
export default
// types/foo/index.d.ts
export default function foo(): string;
// src/index.ts
import foo from 'foo';
foo();
注意蟆融,只有 function
、class
和 interface
可以直接默認(rèn)導(dǎo)出守呜,其他的變量需要先定義出來(lái)型酥,再默認(rèn)導(dǎo)出
export =
在 commonjs 規(guī)范中,我們用以下方式來(lái)導(dǎo)出一個(gè)模塊:
// types/foo/index.d.ts
export = foo;
declare function foo(): string;
declare namespace foo {
const bar: number;
}
UMD 庫(kù)
// types/foo/index.d.ts
export as namespace foo;
export default foo;
declare function foo(): string;
declare namespace foo {
const bar: number;
}
直接擴(kuò)展全局變量
有的第三方庫(kù)擴(kuò)展了一個(gè)全局變量查乒,可是此全局變量的類型卻沒有相應(yīng)的更新過來(lái)弥喉,就會(huì)導(dǎo)致 ts 編譯錯(cuò)誤,此時(shí)就需要擴(kuò)展全局變量的類型玛迄。比如擴(kuò)展 String 類型
interface String {
prependHello(): string;
}
'foo'.prependHello();
在 npm 包或 UMD 庫(kù)中擴(kuò)展全局變量
// types/foo/index.d.ts
declare global {
interface String {
prependHello(): string;
}
}
export {};
// src/index.ts
'bar'.prependHello();
模塊插件
// types/moment-plugin/index.d.ts
import * as moment from 'moment';
declare module 'moment' {
export function foo(): moment.CalendarKey;
}
// src/index.ts
import * as moment from 'moment';
import 'moment-plugin';
moment.foo();
聲明文件中的依賴
// types/moment-plugin/index.d.ts
import * as moment from 'moment';
declare module 'moment' {
export function foo(): moment.CalendarKey;
}
除了可以在聲明文件中通過 import 導(dǎo)入另一個(gè)聲明文件中的類型之外由境,還有一個(gè)語(yǔ)法也可以用來(lái)導(dǎo)入另一個(gè)聲明文件,那就是三斜線指令蓖议。
不建議使用虏杰,當(dāng)在以下幾個(gè)場(chǎng)景下,我們才需要使用三斜線指令替代 import:
- 當(dāng)我們?cè)跁鴮懸粋€(gè)全局變量的聲明文件時(shí)
- 當(dāng)我們需要依賴一個(gè)全局變量的聲明文件時(shí)
// types/jquery-plugin/index.d.ts
/// <reference types="jquery" />
declare function foo(options: JQuery.AjaxSettings): string;
注意勒虾,三斜線指令必須放在文件的最頂端纺阔,三斜線指令的前面只允許出現(xiàn)單行或多行注釋。
自動(dòng)生成聲明文件
如果庫(kù)的源碼本身就是由 ts 寫的修然,那么在使用 tsc 腳本將 ts 編譯為 js 的時(shí)候笛钝,添加 declaration 選項(xiàng),就可以同時(shí)也生成 .d.ts 聲明文件了愕宋。
tsc test.ts -d
發(fā)布聲明文件
此時(shí)有兩種方案:
- 將聲明文件和源碼放在一起
- 將聲明文件發(fā)布到 @types 下
這兩種方案中優(yōu)先選擇第一種方案玻靡。保持聲明文件與源碼在一起,使用時(shí)就不需要額外增加單獨(dú)的聲明文件庫(kù)的依賴了中贝,而且也能保證聲明文件的版本與源碼的版本保持一致囤捻。