Typescript 声明文件 .d.ts

2022-07-21  本文已影响0人  李霖弢

声明文件用于定义类型而非具体的值,不会保留在编译结果的 js 中。

TS编译检查时,变量的声明查找顺序
  1. 当前编译上下文找该变量的定义
  2. 变量所在模块的index.d.ts声明文件中查找(或其package.jsontypes字段指向文件)
    通常由npm包的维护者提供
  3. node_modules/@types/npm包名 查找声明。
    通常由社区提供,以@types/开头的声明文件,如:npm install @types/jquery
  4. 通过配置文件 tsconfig.json 中的 pathsbaseUrl 字段指向的其他目录

全局变量声明

在script模式中,通过declare进行全局变量声明,通过script标签引入,全局生效。

type 和 interface

两者本来就只是类型的定义,因此可以不搭配declare关键字,直接在声明文件中使用
为了防止命名冲突,通常放在namespace

声明全局变量
declare var jQuery: (selector: string) => any;
declare let jQuery: (selector: string) => any;
declare const jQuery: (selector: string) => any;
声明函数

支持函数重载

declare function jQuery(selector: string): any;
declare function jQuery(domReadyCallback: () => any): any;
声明类
declare class Animal {
    name: string;
    constructor(name: string);
    sayHi(): string;
}
声明枚举
declare enum Directions {
    Up,
    Down,
    Left,
    Right
}
声明命名空间

命名空间(namespace)是TS自己的模块化方案,随着ES6的module广泛运用,已不推荐使用。不同于ES6的module,一个文件里可以有多个namespace。
目前通常在声明文件中使用,表示一个对象中具有很多子属性。
通过命名空间.属性来调用内部属性。

declare namespace jQuery {
    function ajax(url: string, settings?: any): void;
    const version: number;
    class Event {
        blur(eventType: EventType): void
    }
    enum EventType {
        CustomClick
    }
}

命名空间也可以嵌套

// src/jQuery.d.ts
declare namespace jQuery {
    function ajax(url: string, settings?: any): void;
    namespace fn {
        function extend(object: any): void;
    }
}
//或
declare namespace jQuery.fn {
    function extend(object: any): void;
}

// src/index.ts
jQuery.ajax('/api/get_something');
jQuery.fn.extend({
    check: function() {
        return this.each(function() {
            this.checked = true;
        });
    }
});
声明合并

同名变量可以重复声明,表示有不同的形状

declare function jQuery(selector: string): any;
declare namespace jQuery {
    function ajax(url: string, settings?: any): void;
}

通过声明合并,还可以为系统变量添加新属性,称为扩展全局变量

interface String {
    prependHello(): string;
}

模块声明

.d.ts文件中,如存在export,则为一个模块声明文件,npm包中即使用该方式。
在模块声明中,只有export导出 + import导入的声明,才会生效。

可以对每个变量分别export,也可以用declare分别声明,并统一export(注意,同全局变量声明文件,type 和 interface 不需要 declare)

// types/foo/index.d.ts
export const name: string;
export interface Options {
    data: any;
}

// types/foo/index.d.ts
declare const name: string;
interface Options {
    data: any;
}

// src/index.ts
import { name, Options } from 'foo';
console.log(name);
let options: Options = {
    data: {
        name: 'foo'
    }
};
commonjs 规范的声明

ts中,对采用commonjs规范的库,可以通过以下方式导入:

const foo = require('foo');
const bar = require('foo').bar;
import * as foo from 'foo';
import { bar } from 'foo';
// types/foo/index.d.ts
export = foo;
declare function foo(): string;
declare namespace foo {
    const bar: number;
}


// 整体导入
import foo = require('foo');
import * as foo from 'foo';
import foo from 'foo';//当启用allowSyntheticDefaultImports时

// 单个导入
import bar = foo.bar;
UMD规范的声明

既可以通过 <script> 标签引入,又可以通过 import 导入的库,需要通过export as namespace将声明好的一个变量声明为全局变量

// types/foo/index.d.ts

export as namespace foo;
export = foo;

declare function foo(): string;
declare namespace foo {
    const bar: number;
}
在module中扩展全局变量

注意声明文件仍然需要导出一个空对象,用来告诉编译器这是一个模块的声明文件

// types/foo/index.d.ts

declare global {
    interface String {
        prependHello(): string;
    }
}

export {};

// src/index.ts

'bar'.prependHello();
模块插件

declare module可用于在一个文件中一次性声明多个模块的类型,或扩展某模块类型

// 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();
上一篇下一篇

猜你喜欢

热点阅读