TypeScript 声明文件与 declare 用法
声明语句
假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了。 我们通常这样获取一个 id 是 foo 的元素
$('#foo');
// or
jQuery('#foo');
但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西
jQuery('#foo');
// ERROR: Cannot find name 'jQuery'.
这时,我们需要使用 declare var 来定义它的类型
declare var jQuery: (selector: string) => any;
jQuery('#foo');
上例中,declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是
jQuery('#foo');
什么是声明文件
通常我们会把声明语句放到一个单独的文件(jQuery.d.ts)中,这就是声明文件
tip
声明文件必需以 .d.ts 为后缀。
一般来说,ts 会解析项目中所有的 *.ts 文件,当然也包含以 .d.ts 结尾的文件。所以当我们将 jQuery.d.ts 放到项目中时, 其他所有 *.ts 文件就都可以获得 jQuery 的类型定义了。
tip
假如仍然无法解析,那么可以检查下 tsconfig.json 中的 files、include 和 exclude 配置,确保其包含了 jQuery.d.ts 文件。
声明语句
declare var&let&const
当我们使用 const 定义时,表示此时的全局变量是一个常量,不允许再去修改它的值了。 而使用 let 或者 var 定义可以去修改声明语句。
tip
一般来说,全局变量都是禁止修改的常量,所以大部分情况都应该使用 const 而不是 var 或 let。
// src/jQuery.d.ts
declare const jQuery: (selector: string) => any;
jQuery('#foo');
// 使用 declare const 定义的 jQuery 类型,禁止修改这个全局变量
jQuery = function (selector) {
return document.querySelector(selector);
};
// ERROR: Cannot assign to 'jQuery' because it is a constant or a read-only property.
tip
需要注意的是,声明语句中只能定义类型,切勿在声明语句中定义具体的实现
declare const jQuery = function (selector) {
return document.querySelector(selector);
};
// ERROR: An implementation cannot be declared in ambient contexts.
declare function
用来定义全局函数的类型。jQuery 其实就是一个函数,所以也可以用 function 来定义
declare function jQuery(selector: string): any;
在函数类型的声明语句中,函数重载也是支持的
// src/jQuery.d.ts
declare function jQuery(selector: string): any;
declare function jQuery(domReadyCallback: () => any): any;
// src/index.ts
jQuery('#foo');
jQuery(function () {
alert('Dom Ready!');
});
declare namespace
namespace 是 ts 早期时为了解决模块化而创造的关键字,中文称为命名空间。
tip
由于历史遗留原因,在早期还没有 ES6 的时候,ts 提供了一种模块化方案,使用 module 关键字表示内部模块。 但由于后来 ES6 也使用了 module 关键字,ts 为了兼容 ES6,使用 namespace 替代了自己的 module,更名为命名空间。 随着 ES6 的广泛应用,现在已经不建议再使用 ts 中的 namespace,而推荐使用 ES6 的模块化方案了,故我们不再需要学习 namespace 的使用了。
namespace 被淘汰了,但是在声明文件中,declare namespace 还是比较常用的,它用来表示全局变量是一个对象,包含很多子属性。
// src/jQuery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
const version: number;
class Event {
blur(eventType: EventType): void;
}
enum EventType {
CustomClick,
}
}
// src/index.ts
jQuery.ajax('/api/get_something');
console.log(jQuery.version);
const e = new jQuery.Event();
e.blur(jQuery.EventType.CustomClick);
declare module 的理解
declare module 声明作用
declare module '*.css';
declare module '*.less';
declare module '*.scss';
declare module '*.sass';
declare module '*.svg';
declare module '*.png';
TS 默认只认 ES 模块。 但如果你用了 Webpack 之类的构建工具,是支持以模块形式导入非 ES 模块的,比如导入了一个 CSS
import 'normalize.css';
这样 TS 不识别,会报错,所以要先把它们声明出来。
tip
目前的三大框架如果你是用脚手架搭建的,已经不再需要你手动去写这几行代码了,框架本身帮你写好了。
支持 CommonJS 和 AMD 的 exports, TypeScript 提供了 export =对象的语法,不能和其他 export 一起使用 对象:是对象,变量,类,接口,命名空间,函数或枚举 export=对象; import x=require('路径') 或 import x from '路径' 两种方式都兼容 node 环境 当"esModuleInterop": true,配置开启时
Typescript (以下简称:ts) 有一个好处是,你可以将 ts 代码生成 CommonJs 规范、AMD 规范,而这二者的规范中,且无法兼容,所以就有了 export =,将二者给统一,以至于让 ts 支持以上规范。 declare module "swiper" { const swiper: { new (element: Element | string, options?: SwiperOptions): Swiper; }; export = swiper; } 如果在 CommonJS 规范中: const Swiper = require('swiper'); 或者 AMD 规范中: require(['swiper'], function(Swiper) { }); 当然,如果你的 @types 不需要支持上面两种规范,那就不需要 export =,因为对于 ts 而言,你只需要这样: import { Swiper } from 'swiper'

还没有留言,来发表第一条吧~