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 小书之入门篇

相关文章
相关标签/搜索