本篇將介紹TypeScript的聲明文件,並簡單演示一下如何編寫和使用聲明文件。本篇也是這個系列的最後一篇。html
TypeScript做爲JavaScript的超集,在開發過程當中不可避免要引用其餘第三方的JavaScript的庫。雖然經過直接引用能夠調用庫的類和方法,可是卻沒法使用TypeScript諸如類型檢查等特性功能。爲了解決這個問題,須要將這些庫裏的函數和方法體去掉後只保留導出類型聲明,而產生了一個描述JavaScript庫和模塊信息的聲明文件。經過引用這個聲明文件,就能夠借用TypeScript的各類特性來使用庫文件了。前端
有如下幾種:全局庫、CommonJS、AMD、UMDnode
全局庫:jquery
早期版本的jQuery就是使用了全局庫的使用方式:git
1 (function( window, undefined ) { 2 var jQuery = function( selector, context ) { 3 return new jQuery.fn.init( selector, context, rootjQuery ); 4 } 5 6 // ...... 7 8 window.jQuery = window.$ = jQuery; 9 })(window);
一般會看到:github
CommonJSnpm
NodeJs模塊化採用的規範,聲明和使用方式以下:json
1 // 模塊定義文件 2 exports.module_name = {}; 3 4 // 模塊調用文件 5 var module = require('模塊定義文件名');
一般會看到:前端框架
AMD框架
前端框架廣泛採用的模塊化的規範,聲明和使用方式以下:
1 // 定義模塊 2 define('模塊名', ['jquery', ...], function($){ 3 // ...... 4 }); 5 6 // 調用模塊 7 require(['模塊名'], function(module) { 8 // ...... 9 });
一般會看到:
UMD
爲了能同時支持上述全部風格的庫聲明方式,就有了通用模塊規範(UMD)。通常會有下面這種聲明方式:
1 // moment.js 2 (function (global, factory) { 3 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 4 typeof define === 'function' && define.amd ? define(factory) : 5 global.moment = factory() 6 }(this, function() { 7 function hooks() { 8 // ...... 9 } 10 11 // ...... 12 return hooks; 13 }));
一般會看到:
經過識別庫的結構,採用不用的聲明方式來編寫聲明文件。
linq.js實現了在JavaScript裏使用Linq語法,在C#有的Linq方法,在它裏面幾乎都有。下面將在nodejs環境裏演示如何編寫和使用linq.js的一個簡單的聲明文件。
1. 建立一個nodejs工程,並經過 npm install linq --save 下載插件包。工程結構以下所示:
1 { 2 "name": "tstest", 3 "version": "1.0.0", 4 "description": "", 5 "main": "index.js", 6 "scripts": { 7 "test": "echo \"Error: no test specified\" && exit 1", 8 "start": "node dist\\main.js" 9 }, 10 "author": "", 11 "license": "ISC", 12 "dependencies": { 13 "linq": "^3.0.5" 14 } 15 }
1 { 2 "compilerOptions": { 3 "target": "es5", 4 "noImplicitAny": false, 5 "module": "commonjs", 6 "removeComments": true, 7 "sourceMap": false, 8 "outDir": "dist" 9 } 10 }
2. 在src目錄下新建文件linq.d.ts
1 interface IEnumerator { 2 current: () => any; 3 moveNext: () => void; 4 dispose: () => void; 5 } 6 7 interface Enumerable { 8 getEnumerator: () => IEnumerator; 9 from: (obj: any) => Enumerable; 10 where: (predicate: string | ((x: any) => boolean)) => Enumerable; 11 toArray: () => Array<any>; 12 } 13 14 declare let linq: Enumerable; 15 16 declare module 'linq' { 17 export = linq; 18 }
3. 仍是在src目錄下新建文件main.ts
1 /// <reference path="linq.d.ts" /> 2 3 import * as Enumerable from 'linq'; 4 5 let result1 = Enumerable.from([1, 2, 3]).where('$>1').toArray(); 6 console.log(`result1 is ${result1}`); 7 8 let result2 = Enumerable.from([1, 2, 3]).where(x => { return x > 2; }).toArray(); 9 console.log(`result2 is ${result2}`);
4. 按下快捷鍵 Ctrl+Shift+B 編譯main.ts文件到dist目錄,生成main.js文件
1 "use strict"; 2 var Enumerable = require('linq'); 3 var result1 = Enumerable.from([1, 2, 3]).where('$>1').toArray(); 4 console.log("result1 is " + result1); 5 var result2 = Enumerable.from([1, 2, 3]).where(function (x) { return x > 2; }).toArray(); 6 console.log("result2 is " + result2);
在控制檯執行命令 npm run start ,查看輸出結果
從這個例子裏能夠看出,聲明文件linq.d.ts裏只定義了linq的類型和方法名稱,在這裏我稱之爲「骨架」。在引用了聲明文件後,便可以經過智能感知和強類型檢查等特性使用linq模塊。編譯時會根據配置文件指定的模塊標準( "module": "commonjs" )生成對應的文件。由於這個例子的運行環境是nodejs,因此採用commonjs標準。
若是是在前端使用,則要採用AMD標準。下面是採用這個標準後編譯生成的文件:
1 define(["require", "exports", 'linq'], function (require, exports, Enumerable) { 2 "use strict"; 3 var result1 = Enumerable.from([1, 2, 3]).where('$>1').toArray(); 4 console.log("result1 is " + result1); 5 var result2 = Enumerable.from([1, 2, 3]).where(function (x) { return x > 2; }).toArray(); 6 console.log("result2 is " + result2); 7 });
linq模塊也支持全局庫的引用方式。經過修改linq.d.ts,支持全局庫引用
1 interface IEnumerator { 2 current: () => any; 3 moveNext: () => void; 4 dispose: () => void; 5 } 6 7 interface Enumerable { 8 getEnumerator: () => IEnumerator; 9 from: (obj: any) => Enumerable; 10 where: (predicate: string | ((x: any) => boolean)) => Enumerable; 11 toArray: () => Array<any>; 12 } 13 14 declare let linq: Enumerable; 15 16 // 全局庫引用 17 export as namespace Enumerable; 18 export = linq;
main.ts調用方式也要修改
1 /// <reference path="linq.d.ts" /> 2 3 let result1 = Enumerable.from([1, 2, 3]).where('$>1').toArray(); 4 console.log(`result1 is ${result1}`); 5 6 let result2 = Enumerable.from([1, 2, 3]).where(x => { return x > 2; }).toArray(); 7 console.log(`result2 is ${result2}`);
編譯生成的main.js
1 var result1 = Enumerable.from([1, 2, 3]).where('$>1').toArray(); 2 console.log("result1 is " + result1); 3 var result2 = Enumerable.from([1, 2, 3]).where(function (x) { return x > 2; }).toArray(); 4 console.log("result2 is " + result2);
TypeScript2.0支持經過npm下載經常使用的模塊的聲明文件,下面借用async模塊簡單演示一下如何引用和使用經常使用模塊的聲明文件。
1. 經過 npm install async --save 下載async模塊
2. 使用 npm install @types/async --save-dev 下載async模塊的聲明文件。下載完成後會在工程的node_modules文件夾下生成存放聲明文件的文件夾
3. main.ts引用聲明文件
1 /// <reference types="async" /> 2 import * as async from 'async'; 3 4 // 並行執行方法 5 async.parallel([ 6 cb => { cb(null, 1); }, 7 cb => { cb(null, 2); }, 8 cb => { cb(null, 3); }, 9 ], (err, results) => { 10 console.log(`results is ${results}`); 11 });
這裏的引用方式和上面的例子略有不一樣。上面的例子是用ref註釋將文件名引用進來,經過npm下載的聲明文件則是引用類型名稱( /// <reference types="async" /> )
4. 編譯以後生成main.js,控制檯執行查看結果
1 "use strict"; 2 var async = require('async'); 3 async.parallel([ 4 function (cb) { cb(null, 1); }, 5 function (cb) { cb(null, 2); }, 6 function (cb) { cb(null, 3); }, 7 ], function (err, results) { 8 console.log("results is " + results); 9 });
更多聲明文件能夠去 http://microsoft.github.io/TypeSearch/ 查找。也許有些模塊如今暫時沒有聲明文件,咱們也能夠本身編寫聲明文件後上傳到 https://github.com/DefinitelyTyped/DefinitelyTyped,一塊兒共建TypeScript的聲明文件倉庫。