JavaScript 是一門動態(tài)弱類型語言,對變量的類型非常寬容。JavaScript使用靈活,開發(fā)速度快,但是由于類型思維的缺失,一點(diǎn)小的修">
×

搭建node服務(wù)(三):使用TypeScript

分類:互聯(lián)網(wǎng)熱點(diǎn) 編輯:新網(wǎng)小青年 瀏覽量:2
2020-07-20 13:33:06

# 搭建node服務(wù)(三):使用TypeScript > JavaScript 是一門動態(tài)弱類型語言,對變量的類型非常寬容。JavaScript使用靈活,開發(fā)速度快,但是由于類型思維的缺失,一點(diǎn)小的修改都有可能導(dǎo)致意想不到的錯誤,使用TypeScript可以很好的解決這種問題。TypeScript是JavaScript的一個超集,擴(kuò)展了 JavaScript 的語法,增加了靜態(tài)類型、類、模塊、接口和類型注解等功能,可以編譯成純JavaScript。本文將介紹如何在node服務(wù)中使用TypeScript。 

一、 安裝依賴 ``` npm install typescript --save npm install ts-node --save npm install nodemon --save ``` 或者 ``` yarn add typescript yarn add ts-node yarn add nodemon ``` 另外,還需要安裝依賴模塊的類型庫: ``` npm install @types/koa --save npm install @types/koa-router --save … ``` 或者 ``` yarn add @types/koa yarn add @types/koa-router … ``` 

 二、 tsconfig.json 當(dāng)使用tsc命令進(jìn)行編譯時,如果未指定ts文件,編譯器會從當(dāng)前目錄開始去查找tsconfig.json文件,并根據(jù)tsconfig.json的配置進(jìn)行編譯。 

 1. 指定文件 可以通過files屬性來指定需要編譯的文件,如下所示: ``` { "files": [ "src/server.ts" ] } ``` 另外也可以通過使用"include"和"exclude"屬性來指定,采用類似glob文件匹配模式,如下所示: ``` { "include": [ "src/**/*" ], "exclude": [ "node_modules", "**/*.spec.ts" ] } ``` 支持的通配符:

 1. * 匹配0或多個字符(不包括目錄分隔符) 

2. ? 匹配一個任意字符(不包括目錄分隔符) 

3. **/ 遞歸匹配任意子目錄 

 2. 常用配置 compilerOptions 屬性用于配置編譯選項,與tsc命令的選項一致,常用的配置如下所示: ``` { "compilerOptions": { // 指定編譯為ECMAScript的哪個版本。默認(rèn)為"ES3" "target": "ES6", // 編譯為哪種模塊系統(tǒng)。如果target為"ES3"或者"ES5",默認(rèn)為"CommonJS",否則默認(rèn)為"ES6" "module": "CommonJS", // 模塊解析策略,"Classic" 或者 "Node"。如果module為"AMD"、"System"或者"ES6",默認(rèn)為"Classic",否則默認(rèn)為"Node" "moduleResolution": "Node", // 是否支持使用import cjs from 'cjs'的方式引入commonjs包 "esModuleInterop": true, // 編譯過程中需要引入的庫。target為"ES5"時,默認(rèn)引入["DOM","ES5","ScriptHost"];target為"ES6"時,默認(rèn)引入["DOM","ES6","DOM.Iterable","ScriptHost"] "lib": ["ES6"], // 編譯生成的js文件所輸出的根目錄,默認(rèn)輸出到ts文件所在的目錄 "outDir": "dist", // 生成相應(yīng)的.map文件 "sourceMap": true }, "include": [ "src/**/*" ], "exclude": [ "node_modules", "**/*.spec.ts" ] } ``` 

 1) target target是編譯目標(biāo),可以指定編譯為ECMAScript的哪個版本,默認(rèn)為"ES3"。ECMAScript的版本有:"ES3" 、"ES5"、 "ES6" 或者 "ES2015"、 "ES2016"、 "ES2017"、"ES2018"、"ES2019"、 "ES2020"、"ESNext"。 

2) module module指定編譯為哪種模塊系統(tǒng),如果target為"ES3"或者"ES5",默認(rèn)為"CommonJS",否則默認(rèn)為"ES6"??蛇x用的模塊系統(tǒng)有:"None"、 "CommonJS"、 "AMD",、"System"、 "UMD"、"ES6"或者"ES2015"、"ESNext"。

3) moduleResolution moduleResolution指定模塊解析策略,模塊解析策略有:"Classic"、"Node",如果module為"AMD"、"System"或者"ES6",默認(rèn)為"Classic",否則默認(rèn)為"Node"。 

示例1: 在/root/src/moduleA.ts中以import { b } from "./moduleB" 方式相對引用一個模塊。 Classic解析策略,查找過程: ``` /root/src/moduleB.ts /root/src/moduleB.d.ts ``` Node解析策略,查找過程: ``` /root/src/moduleB.ts /root/src/moduleB.tsx /root/src/moduleB.d.ts /root/src/moduleB/package.json (如果指定了"types"屬性) /root/src/moduleB/index.ts /root/src/moduleB/index.tsx /root/src/moduleB/index.d.ts ``` 

 示例2: 在/root/src/moduleA.ts中以import { b } from "moduleB" 方式非相對引用一個模塊。 Classic解析策略,查找過程: ``` /root/src/moduleB.ts /root/src/moduleB.d.ts /root/moduleB.ts /root/moduleB.d.ts /moduleB.ts /moduleB.d.ts ``` Node解析策略,查找過程: ``` /root/src/node_modules/moduleB.ts /root/src/node_modules/moduleB.tsx /root/src/node_modules/moduleB.d.ts /root/src/node_modules/moduleB/package.json (如果指定了"types"屬性) /root/src/node_modules/moduleB/index.ts /root/src/node_modules/moduleB/index.tsx /root/src/node_modules/moduleB/index.d.ts /root/node_modules/moduleB.ts /root/node_modules/moduleB.tsx /root/node_modules/moduleB.d.ts /root/node_modules/moduleB/package.json (如果指定了"types"屬性) /root/node_modules/moduleB/index.ts /root/node_modules/moduleB/index.tsx /root/node_modules/moduleB/index.d.ts /node_modules/moduleB.ts /node_modules/moduleB.tsx /node_modules/moduleB.d.ts /node_modules/moduleB/package.json (如果指定了"types"屬性) /node_modules/moduleB/index.ts /node_modules/moduleB/index.tsx /node_modules/moduleB/index.d.ts ``` 

4) esModuleInterop esModuleInterop為true時,表示支持使用import d from 'cjs'的方式引入commonjs包。當(dāng)commonjs模塊轉(zhuǎn)化為esm時,會增加 __importStar 和 __importDefault 方法來處理轉(zhuǎn)化問題。 

示例: cjs為commonjs模塊,代碼如下: ``` module.exports = { name: 'cjs' }; ``` 另外一個模塊以esm方式引用了cjs模塊,代碼如下: ``` import cjsDefault from 'cjs'; import * as cjsStar from 'cjs'; console.log('cjsDefault =', cjsDefault); console.log('cjsStar =', cjsStar); ``` 輸出結(jié)果為: ``` cjsDefault = { name: 'cjs' } cjsStar = { name: 'cjs', default: { name: 'cjs' } } ``` 編譯后生成的代碼如下: ``` var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result = mod; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const cjs_1 = __importDefault(require("cjs")); const cjsStar = __importStar(require("cjs")); console.log('cjsDefault =', cjs_1.default); console.log('cjsStar =', cjsStar); ``` 

 5) lib lib指定編譯過程中需要引入的庫。target為"ES5"時,默認(rèn)引入["DOM","ES5","ScriptHost"];target為"ES6"時,默認(rèn)引入["DOM","ES6","DOM.Iterable","ScriptHost"]。由于本示例TypeScript是用于服務(wù)端的,不需要使用DOM和ScriptHost,所以lib設(shè)為["ES6"]。 

6) outDir 輸出目錄,編譯生成的js文件所輸出的根目錄,默認(rèn)輸出到ts文件所在的目錄。 

 7) sourceMap 是否生成source map文件,通過使用source map 可以在錯誤信息中可以顯示源碼位置。 要想根據(jù)source map 顯示錯誤信息源碼位置,還需要在入口文件引入source-map-support 模塊,如下: ``` import 'source-map-support/register'; ``` 

 三、 腳本命令 入口文件為src/server.ts,package.json中的scripts配置如下: - package.json ``` { "scripts": { "dev": "nodemon --watch src -e ts,tsx --exec ts-node src/server.ts", "build": "tsc", "start": "node dist/server.js" }, … } ``` 

1. 執(zhí)行 npm run dev 命令可以啟動開發(fā)環(huán)境,當(dāng)src下的文件被修改后會自動重新啟動服務(wù)。

 2. 執(zhí)行 npm run build 命令會進(jìn)行編譯,由于tsconfig.json中 outDir 指定輸出目錄為dist,編譯后的js文件將出輸出到dist目錄。 

3. 執(zhí)行 npm run start 命令可以啟動應(yīng)用,啟動前需要執(zhí)行 npm run build 進(jìn)行編譯。 

四、 自定義類型 TypeScript 會自動從 node_modules/@types 目錄獲取模塊的類型定義,引用的模塊都需要安裝對應(yīng)類型庫,如: ``` npm install @types/koa --save ``` 安裝后,會在node_modules/@types 目錄下找到koa 文件夾,該文件夾下有koa相關(guān)的類型定義文件。當(dāng)引用koa模塊時會自動引入node_modules/ 和 node_modules/@types下的 koa 包。如果某個模塊沒有類型庫或者對某個模塊進(jìn)行了擴(kuò)展需要修改類型定義,這時需要引入自定義的類型。

 示例:給koa增加bodyparser中間件 

1. 設(shè)置typeRoots - tsconfig.json ``` { "compilerOptions": { … // 類型聲明文件所在目錄 "typeRoots": ["./node_modules/@types", "./src/types"], }, "include": [ "src/**/*" ], "exclude": [ "node_modules", "**/*.spec.ts" ] } ``` src/types是存放自定義類型的目錄,本示例中src/types目錄已被include包含,如果自定義的類型目錄未被include包含還需要在include中添加該目錄。

 2. 編寫類型定義文件 - src/types/koa/index.d.ts ``` import * as Koa from "koa"; declare module "koa" { interface Request { body?: object; rawBody: string; } } ``` 這里給koa的request對象增加body和rawBody兩個屬性,分別用于存放請求體的json對象和原始字符串。 

3. 編寫 jsonBodyParser 插件 - src/middleware/jsonBodyParser.ts ``` import Koa from "koa"; function getRawBody(ctx: Koa.Context): Promise { return new Promise((resolve, reject) => { try { let postData: string = ''; ctx.req.addListener('data', (data) => { postData += data; }); ctx.req.on('end', () => { resolve(postData); }); } catch (e) { console.error('獲取body內(nèi)容失敗', e); reject(e); } }) } export default function jsonBodyParser (): Koa.Middleware { return async(ctx: Koa.Context, next: Koa.Next) => { const rawBody: string = await getRawBody(ctx); const request: Koa.Request = ctx.request; request.rawBody = rawBody; if (rawBody) { try { request.body = JSON.parse(rawBody); } catch (e) { request.body = {}; } } await next(); }; } ``` jsonBodyParser()會返回一個koa中間件,這個中間件將獲取請求體的內(nèi)容,將原始內(nèi)容字符串賦值到ctx.request.rawBody,將請求體內(nèi)容json對象賦值到ctx.request.body。由于src/types/koa/index.d.ts自定義類型已經(jīng)擴(kuò)展了Koa.Request的這兩個屬性,執(zhí)行npm run build命令,使用 tsc 進(jìn)行編譯,可以編譯成功。但是當(dāng)執(zhí)行 npm run dev 時,會提示編譯錯誤,那是因為ts-node默認(rèn)不會根據(jù)配置中的files、include 和 exclude 加載所有ts文件,而是從入口文件開始根據(jù)引用和依賴加載文件。最簡單的解決辦法就是在 ts-node 命令后增加 --files 參數(shù),表示按配置的files、include 和 exclude加載ts文件,如下: - package.json ``` { "scripts": { "dev": " nodemon --watch src -e ts,tsx --exec ts-node --files src/server.ts", } } ``` 

五、 說明 本文介紹了如何在node服務(wù)中使用TypeScript,具體的TypeScript語法規(guī)則網(wǎng)上有很多相關(guān)的資料,這里就不再介紹了。本文相關(guān)的代碼已提交到GitHub以供參考, 項目地址:[https://github.com/liulinsp/node-server-typescript-demo]。 


聲明:免責(zé)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn)自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認(rèn)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請發(fā)

送郵件至:operations@xinnet.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,本站將立刻刪除涉嫌侵權(quán)內(nèi)容。本站原創(chuàng)內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時

需注明出處:新網(wǎng)idc知識百科

免費(fèi)咨詢獲取折扣

Loading