声明文件用于定义类型而非具体的值,不会保留在编译结果的 js 中。
TS编译检查时,变量的声明查找顺序
- 当前编译上下文找该变量的定义
- 变量所在模块的
index.d.ts
声明文件中查找(或其package.json
中types
字段指向文件)
通常由npm包的维护者提供 -
node_modules/@types/npm包名
查找声明。
通常由社区提供,以@types/
开头的声明文件,如:npm install @types/jquery
- 通过配置文件
tsconfig.json
中的paths
和baseUrl
字段指向的其他目录
全局变量声明
在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规范的库,可以通过以下方式导入:
- commonjs语法:
const foo = require('foo');
const bar = require('foo').bar;
- ESM语法:
import * as foo from 'foo';
import { bar } from 'foo';
- TS新增语法
import + require
和export =
搭配使用:
// 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();
网友评论