摘要:不過(guò),相對(duì)于靜態(tài)類型檢查帶來(lái)的好處,這些代價(jià)是值得的。當(dāng)然少不了的模塊化標(biāo)準(zhǔn),雖然到目前為止和大部分瀏覽器都還不支持它。本身支持兩種模塊化方式,一種是對(duì)的模塊的微小擴(kuò)展,另一種是在發(fā)布之前本身模仿的命名空間。有一種情況例外。
TypeScript 帶來(lái)的最大好處就是靜態(tài)類型檢查,所以在從 JavaScript 轉(zhuǎn)向 TypeScript 之前,一定要認(rèn)識(shí)到添加類型定義會(huì)帶來(lái)額外的工作量,這是必要的代價(jià)。不過(guò),相對(duì)于靜態(tài)類型檢查帶來(lái)的好處,這些代價(jià)是值得的。當(dāng)然,TypeScript 允許不定義類型或者將所有類型定義為 any,但如果這樣做,TypeScript 帶來(lái)的大部分靜態(tài)檢查功能都會(huì)失去作用,換言之,也就沒(méi)必要使用 TypeScript 了。
模塊化在轉(zhuǎn)換之前還要注意的一個(gè)問(wèn)題就是模塊化。早期的 JavaScript 代碼基本上是每個(gè) HTML 頁(yè)面對(duì)應(yīng)一個(gè)或幾個(gè) JavaScript 腳本,那時(shí)候的 JavaScript 代碼中很少有模塊化的概念。不過(guò)隨著 Web 2.0 的興起,大量的工作從后端移到前端,JavaScript 程序變得越來(lái)越復(fù)雜,模塊化成為剛需,大量的模塊化框架隨之而來(lái),其中比較有名的有 RequestJS 及其帶來(lái)的 AMD 標(biāo)準(zhǔn),還有 SeaJS 帶來(lái)的 CMD 標(biāo)準(zhǔn)。而隨著 Node.js 的興起以及 JavaScript 的全?;钟辛?CommonJS 標(biāo)準(zhǔn)。之后又出現(xiàn)了廣為使用的 SystemJS。當(dāng)然少不了 ES6 的模塊化標(biāo)準(zhǔn),雖然到目前為止 Node.js 和大部分瀏覽器都還不支持它。
TypeScript 本身支持兩種模塊化方式,一種是對(duì) ES6 的模塊的微小擴(kuò)展,另一種是在 ES6 發(fā)布之前本身模仿 C# 的命名空間。大部分使用命令空間的場(chǎng)景都可以使用 ES6 模塊化標(biāo)準(zhǔn)來(lái)代替。我們先來(lái)看一看兩種模塊化方式區(qū)別。
命名空間使用命令空間寫(xiě)的 TS 腳本在轉(zhuǎn)譯成 JS 后,可以不使用任何模塊加載框架,直接在頁(yè)面中加載即可使用。不過(guò)很遺憾,這種方式轉(zhuǎn)義出來(lái)的 JS 程序不能直接在 Node.js 中使用。因?yàn)?tsc 不為會(huì)命名空間形式的模塊生成 modules.exports 對(duì)象以及 require 語(yǔ)句。
有一種情況例外。將所有 .ts 文件轉(zhuǎn)譯成一個(gè) .js,假設(shè)叫 all.js,那么它可以通過(guò) node all 來(lái)運(yùn)行。這種情況下不需要任何模塊的導(dǎo)入導(dǎo)出。
不過(guò)在瀏覽器環(huán)境中,嚴(yán)格的按照依賴順序引入生成的 .js 文件是可行的。早期沒(méi)有使用模塊化的 JS 文件就可以使用“命名空間”形式的模塊化寫(xiě)法,甚至可以將原來(lái)成百上千行的大型 JS 源文件,拆分成若干小的 TS 文件,再通過(guò) tsc --outfile 輸出單一 JS 文件來(lái)使用,這樣既能實(shí)現(xiàn)模塊化重構(gòu),又能不改變?cè)械?HTML(或其它動(dòng)態(tài)頁(yè)面文件)的代碼。
還有一點(diǎn)需要注意的是,在指定生成單一輸出文件的情況下,TypeScript 不會(huì)通過(guò)代碼邏輯去檢查模塊間的依賴關(guān)系。默認(rèn)情況下它會(huì)按文件名的字母序逐個(gè)轉(zhuǎn)譯 .ts 文件,除非源文件中通過(guò) ///
在 TypeScript 使用 ES6 模塊語(yǔ)法來(lái)實(shí)現(xiàn)模塊化的情況下,tsc 允許通過(guò) module 參數(shù)來(lái)指定生成的 .js 會(huì)應(yīng)用于何種模塊化框架,默認(rèn)的是 commonjs,其它比較常用的還有 amd、system 等。
顯然,如果原來(lái)的 JS 程序使用了 AMD 框架,在轉(zhuǎn)換成 TS 的時(shí)候,就可以使用 ES6 模塊寫(xiě)法,并通過(guò) tsc --module amd 來(lái)輸出對(duì)應(yīng)的 JS 文件,同樣不需要修改原來(lái)的頁(yè)面文件。
但是,如果原來(lái)的 JS 文件沒(méi)有使用任何模塊框架的情況下,轉(zhuǎn)換為采用 ES6 模塊寫(xiě)法的 TS 代碼,在構(gòu)建的時(shí)候就會(huì)麻煩一點(diǎn)。這種情況下即使構(gòu)建成單一輸出文件,仍然會(huì)需要模塊化框架的支持,比如需要 AMD 的 define 和 require,或者需要 System 的 API 支持。
為了避免引入模塊化框架,可以考慮以 commonjs 標(biāo)準(zhǔn)輸出 JS,然后通過(guò) Webpack 來(lái)把所有生成的 JS 打包成單一文件。這里既然用到了 Webpack,構(gòu)建配置就可以更靈活了,因?yàn)?Webpack 可以指定多個(gè) entry,可以有多個(gè)輸出,它會(huì)通過(guò) import ... 轉(zhuǎn)譯成的 require(...) 自動(dòng)檢查依賴項(xiàng)。而且 Webpack 還可以使用 ts-loader 直接處理 .ts 文件而不需要先使用 tsc 來(lái)進(jìn)行轉(zhuǎn)譯。如果在 TS 中用到了高版本 ECMAScript 語(yǔ)法,比如 async/await,還可以通過(guò) babel-loader 來(lái)增加一層處理……非常靈活。
但這里往往會(huì)有一個(gè)問(wèn)題,生成的 .js 中所有定義都不在全局范圍,那么腳本引入網(wǎng)頁(yè)之后,如何使用其中定義的內(nèi)容?這需要借助全局對(duì)象 window——這里不需要考慮 Node.js 的全局對(duì)象 global,因?yàn)樵?Node.js 下一般是采用模塊化的方式引入,不需要向全局對(duì)象注入什么東西。
向 window 注入對(duì)象(或函數(shù)、值等)的方法也很簡(jiǎn)單,分兩步:申明、賦值,比如:
import MyApi from "./myapi"; declare global { interface Window { mime: MyApi; } } window.mime = new MyApi();常用的構(gòu)建配置
我們?cè)缙陧?xiàng)目中使用 TypeScript 的命名空間,不過(guò)最近幾乎都重構(gòu)成 ES6 模塊方式了。由于會(huì)用到 async 函數(shù),所以一般會(huì)配置 TypeScript 輸出 ES2017 代碼,再通過(guò) Babel 轉(zhuǎn)譯成 ES5 代碼,最后由 Webpack 打包輸出。
tsconfig.json{ "compilerOptions": { "module": "commonjs", "target": "es2017", "lib": [ "dom", "es6", "dom.iterable", "scripthost", "es2017" ], "noImplicitAny": false, "sourceMap": false } }
在 target 為 es5 或 es6 的時(shí)候,TypeScript 會(huì)有默認(rèn)的 lib 列表,這在官方文檔中有詳細(xì)說(shuō)明。target 定義為 es2017 是為了支持 async 函數(shù),但這個(gè)配置沒(méi)有默認(rèn) lib 列表,所以參考官方文檔對(duì) --target es6 使用的 lib 列表,補(bǔ)充 es2017 類型庫(kù)即可。
webpack.config.js這里使用了 Webpack2 的配置格式。
module.exports = { entry: { index: "./js/index" }, output: { filename: "[name].js" }, devtool: "source-map", resolve: { extensions: [".ts"] }, module: { rules: [ { test: /.ts$/, use: [ { loader: "babel-loader", options: { presets: ["es2015", "stage-3"] } }, "ts-loader" ], exclude: /node_modules/ } ] } };gulp task
如果還使用 gulp,任務(wù)是這樣寫(xiě)的
const gulp = require("gulp"); const gutil = require("gulp-util"); // 轉(zhuǎn)譯JavaScript gulp.task("webpack", () => { const webpack = require("webpack-stream"); const config = require("./webpack.config.js"); return gulp.src("./js/**/*.ts") .pipe(webpack(config, require("webpack"))) .on("error", function(err) { gutil.log(err); this.emit("end"); }) .pipe(gulp.dest("../www/js")); });
這里需要注意的是 webpack-stream 默認(rèn)使用的是 webpack1,而我們的配置需要 webpack2,所以為它指定第二個(gè)參數(shù),一個(gè)特定版本的 webpack 實(shí)例 (由 require("webpack") 導(dǎo)入的)。
需要的 Node 模塊從上面的構(gòu)建配置中不難總結(jié)出構(gòu)建過(guò)程需要安裝的 Node 模塊,有這樣一些
gulp
gulp-util
webpack-stream
webpack
ts-loader
typescript
babel-loader
babel-core
babel-preset-es2015
babel-preset-stage-3
在 Node.js 環(huán)境直接運(yùn)行 .ts在 Node.js 中可以通過(guò) ts-node 包來(lái)直接運(yùn)行 TypeScript 代碼。需要做的只是在入口代碼文件(當(dāng)然是個(gè) .js 代碼)中添加一句
require("ts-node").register({ /* options */ })
或者
require("ts-node/register")
因?yàn)?Node.js 7.6 開(kāi)始已經(jīng)直接支持 async 函數(shù)語(yǔ)法,所以即使用到了這個(gè)語(yǔ)法,也不用擔(dān)心 ts-node 在內(nèi)存的轉(zhuǎn)譯結(jié)果不能運(yùn)行。
入口文件仍然必須是 .js 文件,這是個(gè)小小的遺憾,不過(guò)對(duì)于使用 Node.js 寫(xiě)構(gòu)建腳本的用戶來(lái)說(shuō),有兩個(gè)好消息:gulp 和 webpack 都直接支持 .ts 入口(或配置)文件。比如以 gulp 為例,可以定義 gulpfile.ts (注意擴(kuò)展名是 .ts) 如下
import * as gulp from "gulp"; gulp.task("hello", () => { console.log("hello gulp"); });
不過(guò) gulp 也是通過(guò) ts-node 模塊來(lái)實(shí)現(xiàn)使用 TypeScript 的,而 ts-node 的功能依賴于 typescript,所以別忘了安裝這兩個(gè)模塊。
擴(kuò)展閱讀從 JavaScript 到 TypeScript - 聲明類型
從 JavaScript 到 TypeScript - 泛型
從 JavaScript 到 TypeScript - 接口
關(guān)注作者的公眾號(hào)“邊城客?!?→
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/82387.html
摘要:和類似的預(yù)處理器還有等。的用處非常多,包括給自動(dòng)加前綴使用下一代語(yǔ)法等,目前越來(lái)越多的人開(kāi)始用它,它很可能會(huì)成為預(yù)處理器的最終贏家。 webpack實(shí)戰(zhàn) 查看所有文檔頁(yè)面:全棧開(kāi)發(fā),獲取更多信息??祚R加鞭,加班加點(diǎn),終于把這個(gè)文檔整理出來(lái)了,順便深入地學(xué)習(xí)一番,鞏固知識(shí),就是太累人,影響睡眠時(shí)間和質(zhì)量。極客就是想要把事情做到極致,開(kāi)始了就必須到達(dá)終點(diǎn)。 原文鏈接:webpack實(shí)戰(zhàn),原...
摘要:第一個(gè)完全使用重構(gòu)的純項(xiàng)目已經(jīng)上線并穩(wěn)定運(yùn)行了。測(cè)試用例的改造前邊的改為大多數(shù)原因是因?yàn)閺?qiáng)迫癥所致。但是測(cè)試用例的改造則是一個(gè)能極大提高效率的操作。 最近的一段時(shí)間一直在搞TypeScript,一個(gè)巨硬出品、賦予JavaScript語(yǔ)言靜態(tài)類型和編譯的語(yǔ)言。 第一個(gè)完全使用TypeScript重構(gòu)的純Node.js項(xiàng)目已經(jīng)上線并穩(wěn)定運(yùn)行了。 第二個(gè)前后端的項(xiàng)目目前也在重構(gòu)中,關(guān)于前...
摘要:擁抱異步編程縱觀發(fā)展史也可以說(shuō)成開(kāi)發(fā)的發(fā)展史,你會(huì)發(fā)現(xiàn)異步徹底改變了這場(chǎng)游戲??梢赃@么說(shuō),異步編程已成為開(kāi)發(fā)的根基。這也是你應(yīng)盡早在上投入大量時(shí)間的一處核心知識(shí)點(diǎn),這其中包含和等重要概念。這也是最突出的一項(xiàng)貢獻(xiàn)。 原文地址:Medium - Learning How to Learn JavaScript. 5 recommendations on how you should spend ...
摘要:所以,如果你也考慮開(kāi)始使用,不妨也看一下。使用模塊中,模塊的使用方法與一致。安裝好定義文件之后,如果使用等對(duì)支持較好的編輯器,則會(huì)提供更加強(qiáng)大的代碼提示功能。如果使用配合的,則可以方便地構(gòu)建瀏覽器可以運(yùn)行的代碼。 TypeScript所做的,是在JavaScript的基礎(chǔ)上加入了類型,TypeScript編譯器將TypeScript編譯成JavaScript,可以在瀏覽器或者nodej...
閱讀 1587·2021-08-09 13:47
閱讀 2827·2019-08-30 15:55
閱讀 3571·2019-08-29 15:42
閱讀 1172·2019-08-29 13:45
閱讀 3084·2019-08-29 12:33
閱讀 1801·2019-08-26 11:58
閱讀 1049·2019-08-26 10:19
閱讀 2478·2019-08-23 18:00