TypeScript 聲明文件的書寫

一般,經常使用的聲明文件,社區都幫咱們作好了。在此做爲筆記分享,仍是要了解下當第三方庫沒有時,本身該如何書寫。在動手前,先分析下場景:javascript

全局變量

  • 最簡單直接,經過標籤 <script> 引入,注入全局變量 xxx
  • npm install @types/xxx --save-dev 安裝,不準任何配置;
  • 聲明文件 xxx.d.ts 存放當前項目中,建議和其餘 *.ts 都存放在 src 目錄下(沒有生效,可檢查 tsconfig.json 中的 file、include、exclude 等配置);
聲明語句 含義 舉例
declare vardeclare constdeclare let 聲明 全局變量 declareVar.ts
declare function 聲明 全局方法 declareFunction.ts
declare class 聲明 全局類 declareClass.ts
declare enum 聲明 全局枚舉類型 declareEnum.ts
declare namespace 聲明 全局對象 declareNamespace.ts
interfacetype 聲明 全局類型 declareInterface.ts 和 declareType.ts

declare vardeclare constdeclare 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 改成 namespacegit

不建議用: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

interfacetype

// 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);
複製代碼

npm 包

經過 import xxx from 'xxx' 導入,符合 ES6 模塊規範。知道怎麼引入 npm 包,還得知道怎麼去建立 npm 包。json

聲明文件存放位置

和 npm 包綁定在一塊兒(npm 發佈者也提供了聲明文件,良心發佈者)

場景是當接手一個項目,一是查找其 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.ts0.1.3/export.ts
export namespace 導出對象(含子屬性) types/export/index.d.ts0.1.3/export.ts
export default 導出默認(ES6)(推薦) types/exportDefault/*.d.ts0.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 中可直接導出 functionclassinterface

// 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 ... requireexport = 都是 Typescript 爲了兼容 AMD 規範和 commonjs 規範建立的語法,因爲不經常使用因此也不推薦用。而是推薦使用 ES6 標準的 export defaultexport(你們都這麼用)。

UMD 庫

通用模塊定義(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);
複製代碼

擴展全局變量

本次代碼 Github

你能夠...

上一篇:Typescript 聲明文件

下一篇:Typescript 串講

目錄:Typescript 小書之入門篇

相關文章
相關標籤/搜索