一般,經常使用的聲明文件,社區都幫咱們作好了。在此做爲筆記分享,仍是要了解下當第三方庫沒有時,本身該如何書寫。在動手前,先分析下場景:javascript
<script>
引入,注入全局變量 xxx
;npm install @types/xxx --save-dev
安裝,不準任何配置;xxx.d.ts
存放當前項目中,建議和其餘 *.ts
都存放在 src 目錄下(沒有生效,可檢查 tsconfig.json
中的 file、include、exclude
等配置);聲明語句 | 含義 | 舉例 |
---|---|---|
declare var 、declare const 、declare let |
聲明 全局變量 | declareVar.ts |
declare function |
聲明 全局方法 | declareFunction.ts |
declare class |
聲明 全局類 | declareClass.ts |
declare enum |
聲明 全局枚舉類型 | declareEnum.ts |
declare namespace |
聲明 全局對象 | declareNamespace.ts |
interface 、type |
聲明 全局類型 | declareInterface.ts 和 declareType.ts |
declare var
、declare const
、declare let
// jQuery2.d.ts
declare const jQuery2: (selector: string) => any;
複製代碼
// declareVar2.ts
jQuery2('#root');
複製代碼
declare function
// declareFunction.d.ts
declare function declareFunc(selector: string): any;
複製代碼
// declareFunction.ts
declareFunc('#root');
複製代碼
declare class
// declareClass.d.ts
declare class DeclareClass {
name: string;
constructor(name: string);
showName(): string;
showName2() {
return `我是${this.name}`;
}
}
// 0.1.3/declareClass.d.ts:5:17 - error TS1183: An implementation cannot be declared in ambient contexts.
// 5 showName2() {
複製代碼
// declareClass.ts
let declareClass = new DeclareClass('class');
複製代碼
declare class
只定義類型,不具體實現( 例子中 showName2
是具體實現因此報錯了)。java
declare enum
// declareEnum.d.ts
declare enum DeclareEnum {
man,
woman
}
複製代碼
// declareEnum.d.ts
let person = [ DeclareEnum.woman, DeclareEnum.man ];
複製代碼
declare namespace
namespace
第一次見,是 ts 早期爲了解決模塊化造的關鍵字,顧名思義是命名空間的意思。node
由來:前面說了 ts 用
namespace
解決模塊化,那模塊化單詞是module
,可後來 ES6 也是用了module
,因爲 ts 要兼容 ES6,不得已將module
改成namespace
。git
不建議用:ES6 的出現,ts 不建議再用
namespace
來解決模塊化問題,而是推薦使用 ES6 的模塊化方案(ts 仍是很包容的,一切爲了程序員的便利)。程序員
瞭解其原理:雖然
namespace
不建議用了,但declare namespace
仍是經常使用的,表示全局變量的一個對象,因此就有子屬性。github
// declareNamespace.d.ts
declare namespace declareNamespace {
const name: string;
function showName(name: string): void;
class Gender {
showGender(gender: string): void;
}
enum Direction { up, right, down, left }
namespace ns {
function showNs(name: string): void;
}
}
複製代碼
// declareNamespace.ts
declareNamespace.showName('declareNamespace');
declareNamespace.ns.showNs('ns');
複製代碼
注:在聲明對象中可繼續嵌入聲明對象。typescript
interface
和 type
// interface.d.ts
interface Options {
position?: 'TOP' | 'BOTTOM';
data?: any;
}
declare namespace modal {
function open(title: string, options?: Options): void;
}
複製代碼
// interface.ts
let options: Options = {
position: 'top',
data: {
width: 200
}
}
modal.open('新增', options);
複製代碼
上面 interface
沒什麼問題,可是它是暴露在全局類型中的,因此最好存放在 namespace
中,可改寫爲npm
// interface2.d.ts
declare namespace modal {
interface Options {
position?: 'top' | 'bottom';
data?: any;
}
function open(title: string, options?: Options): void;
}
複製代碼
// interface2.ts
let options: modal.Options = {
position: 'top',
data: {
width: 200
}
}
modal.open('新增', options);
複製代碼
經過 import xxx from 'xxx'
導入,符合 ES6 模塊規範。知道怎麼引入 npm 包,還得知道怎麼去建立 npm 包。json
場景是當接手一個項目,一是查找其 npm 包可看 package.json
中的 types
,二是查看有無 xxx/index.d.ts
聲明文件。爲了便於本身和他人,請將聲明文件和 npm 包綁定在一塊兒(若是之後本身發佈 npm 包)。模塊化
@types
(沒有和 npm 包綁定在一塊兒,由其餘人發佈)因爲種種狀況,有的 npm 包並無聲明文件,這個時候試着安裝 xxx(npm install @types/xxx -S
)來判斷 @types
是否存在聲明文件(爲了在 ts 便利使用,其餘人補足了對應的聲明文件,但只能發佈到 @types
裏)。
一是建立在 node_modules/@types/xxx/index.d.ts
,這種方式不須要額外配置(好處),可是 node_modules
是不穩定的,由於 node_modules
目錄不會發布到倉庫、沒法版本回溯、有刪除風險、多人團隊應用亂等問題,因此不建議使用;二是建立 types
目錄,專門存放本身寫的聲明文件,如 @types/xxx/index.d.ts
,此刻須要 tsconfig.json
配合,成功規避掉第一種方法產生的問題;
project
├── src
| └── index.ts
├── types
| └── xxx
| └── index.d.ts
└── tsconfig.json
複製代碼
tsconfig.json
內容{
"compilerOptions": {
"module": "commonjs",
"baseUrl": "./",
"paths": {
"*": ["types/*"]
}
}
}
複製代碼
語法 | 含義 | 示例 |
---|---|---|
export | 導出變量 | types/export/index.d.ts 和 0.1.3/export.ts |
export namespace | 導出對象(含子屬性) | types/export/index.d.ts 和 0.1.3/export.ts |
export default | 導出默認(ES6)(推薦) | types/exportDefault/*.d.ts 和 0.1.3/exportDefault.ts |
export = commonjs | 導出模塊(不推薦) |
export
導出變量前面談到過全局變量的聲明文件方式,npm 包聲明文件和其有必定區別。
declare
聲明全局變量,就只是聲明一個普通變量(局部變量);export
導出;import
導入而後使用,這個和 ES6 同樣(無學習成本);下面就本身建立聲明文件,推薦寫在 types
目錄下,後續也是如此。
// types/export/index.d.ts
export const name: string;
export function showName(): string;
export class Star {
constructor(name: string);
say(): string;
}
export enum Gender {
woman,
man
}
export interface Options {
position?: 'TOP' | 'BOTTOM';
data?: any;
}
export namespace declareNamespace {
const name: string;
namespace ns {
function showNs(name: string): string;
}
}
複製代碼
// 0.1.3/export.ts
import { name, showName, Star, Gender, Options, declareNamespace } from '../types/export';
console.log(name);
let myName = showName();
let newStar = new Star('pr');
let gender = [Gender.woman, Gender.man];
let options: Options = {
position: 'TOP',
data: { name: 'pr', age: 18 }
}
console.log(declareNamespace.name);
declareNamespace.ns.showNs('ns');
複製代碼
export default
導出默認(ES6)export default
不管是 ES6 仍是 Typescript 都是直接默認導出。在 Typescript 中可直接導出 function
、class
和 interface
。
// types/exportDefault/function.d.ts
export default function showName(): string;
複製代碼
// types/exportDefault/class.d.ts
export default class Star {
constructor(name: string);
say(): string;
}
複製代碼
// types/exportDefault/interface.d.ts
export default interface Options {
position?: 'TOP' | 'BOTTOM';
data?: any;
}
複製代碼
// types/exportDefault/enum.d.ts
declare enum Gender {
woman,
man
}
export default Gender;
複製代碼
// types/exportDefault/namespace.d.ts
declare namespace declareNamespace {
const name: string;
namespace ns {
function showNs(name: string): string;
}
}
export default declareNamespace;
複製代碼
export =
導出模塊commonjs 規範中,導出一個模塊能夠
// 導出總體
module.exports = xxx;
// 導出單個
exports.xxx = xxx;
複製代碼
在 Typescript 中,對於 commonjs 模塊導出,有多種導入方式
// 導入總體
const xxx = require('xxx');
import * as xxx from 'xxx';
import xxx = require('xxx');
// 導入單個
const fn = require('xxx').fn;
import { fn } from 'xxx';
import fn = xxx.fn;
複製代碼
注:
import ... require
和export =
都是 Typescript 爲了兼容 AMD 規範和 commonjs 規範建立的語法,因爲不經常使用因此也不推薦用。而是推薦使用 ES6 標準的export default
和export
(你們都這麼用)。
通用模塊定義(Universal Module Definition),UMD 庫指那些能夠經過 <script>
標籤引入,又能夠經過 import
導入的庫。和 npm 包的聲明文件不一樣的是,須要額外聲明一個全局變量。
// types/umd/index.d.ts
export as namespace umd;
export default umd;
// export = umd;
declare function umd(): string;
declare namespace umd {
let ns: string;
function showNs(ns: number): string;
}
複製代碼
// 0.1.3/umd.ts
import umd from '../types/umd';
umd();
umd.ns = '18';
umd.showNs(18);
複製代碼