# 搭建node辦事(三):採用TypeScript
JavaScript 是一門動態弱類型語言,對變量的類型極度包容。JavaScript採用敏捷,開闢速度快,不過由于類型思維的缺失,一點小的改動都有可能導致意想不到的過錯,採用TypeScript可以很好的解決這種疑問。TypeScript是JavaScript的一個超集,開拓了 JavaScript 的語法,提升了靜態類型、類、模塊、接口和類型注解等性能,可以編譯成純JavaScript。本文將介紹如何在node辦事中採用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 typeskoa –save
npm install typeskoa-router –save
…
“`
或者
“`
yarn add typeskoa
yarn add typeskoa-router
…
“`
二、 tsconfig.json
當採用tsc號召進行編譯時,假如未指定ts文件,編譯器會從當前目次開端去查找tsconfig.json文件,并依據tsconfig.json的部署進行編譯。
1. 指定文件
可以通過files屬性來指定需求編譯的文件,如下所示:
“`
{
“files” [
“srcserver.ts”
]
}
“`
另有也可以通過採用”include”和”exclude”屬性來指定,采用相似glob文件匹配模式,如下所示:
“`
{
“include” [
“src***”
],
“exclude” [
“node_modules”,
“***.spec.ts”
]
}
“`
支持的通配符:
1. * 匹配0或多個字符(不包含有目次分隔符)
2. ? 匹配一個任意字符(不包含有目次分隔符)
3. ** 遞歸匹配任意子目次
2. 常用部署
pilerOptions 屬性用于部署編譯選項,與tsc號召的選項一致,常用的部署如下所示:
“`
{
“pilerOptions” {
指定編譯為ECMAScript的哪個版本。默以為”ES3″
“target” “ES6″,
編譯為哪種模塊體制。假如target為”ES3″或者”ES5″,默以為”CommonJS”,不然默以為”ES6”
“module” “CommonJS”,
模塊分析手段,”Classic” 或者 “Node”。假如module為”AMD”、”System”或者”ES6″,默以為”Classic”,不然默以為”Node”
“moduleResolution” “Node”,
是否支持採用import cjs from ‘cjs’的方式引入monjs包
“esModuleInterop” true,
編譯過程中需求引入的庫。target為”ES5″時,默認引入[“DOM”,”ES5″,”ScriptHost”];target為”ES6″時,默認引入[“DOM”,”ES6″,”DOM.Iterable”,”ScriptHost”]
“lib” [“ES6”],
編譯生成的js文件所輸出的根目次,默投降出到ts文件地點的目次
“outDir” “dist”,
生成相應的.map文件
“sourceMap” true
},
“include” [
“src***”
],
“exclude” [
“node_modules”,
“***.spec.ts”
]
}
“`
1) target
target是編譯目的,可以指定編譯為ECMAScript的哪個版本,默以為”ES3″。ECMAScript的版本有:”ES3″ 、”ES5″、 “ES6” 或者 “ES2024″、 “ES2024″、 “ES2024″、”ES2024″、”ES2024″、 “ES2024″、”ESNext”。
2) module
module指定編譯為哪種模塊體制,假如target為”ES3″或者”ES5″,默以為”CommonJS”,不然默以為”ES6″。可選用的模塊體制有:”None”、 “CommonJS”、 “AMD”,、”System”、 “UMD”、”ES6″或者”ES2024″、”ESNext”。
3) moduleResolution
moduleResolution指定模塊分析手段,模塊分析手段有:”Classic”、”Node”,假如module為”AMD”、”System”或者”ES6″,默以為”Classic”,不然默以為”Node”。
示例1:
在rootsrcmoduleA.ts中以import { b } from “.moduleB” 方式相對引用一個模塊。
Classic分運彩報馬仔 nba析手段,查找過程:
“`
rootsrcmoduleB.ts
rootsrcmoduleB.d.ts
“`
Node分析手段,查找過程:
“`
rootsrcmoduleB.ts
rootsrcmoduleB.tsx
rootsrcmoduleB.d.ts
rootsrcmoduleBpackage.json (假如指定了”types”屬性)
rootsrcmoduleBindex.ts
rootsrcmoduleBindex.tsx
rootsrcmoduleBindex.d.ts
“`
示例2:
在rootsrcmoduleA.ts中以import { b } from “moduleB” 方式非相對引用一個模塊。
Classic分析手段,查找過程:
“`
rootsrcmoduleB.ts
rootsrcmoduleB.d.ts
rootmoduleB.ts
rootmoduleB.d.ts
moduleB.ts
moduleB.d.ts
“`
Node分析手段,查找過程:
“`
rootsrcnode_modulesmoduleB.ts
rootsrcnode_modulesmoduleB.tsx
rootsrcnode_modulesmoduleB.d.ts
rootsrcnode_modulesmoduleBpackage.json (假如指定了”types”屬性)
rootsrcnode_modulesmoduleBindex.ts
rootsrcnode_modulesmoduleBindex.tsx
rootsrcn運彩中華韓國ode_modulesmoduleBindex.d.ts
rootnode_modulesmoduleB.ts
rootnode_modulesmoduleB.tsx
rootnode_modulesmoduleB.d.ts
rootnode_modulesmoduleBpackage.json (假如指定了”types”屬性)
rootnode_modulesmoduleBindex.ts
rootnode_modulesmoduleBindex.tsx
rootnode_modulesmoduleBindex.d.ts
node_modulesmoduleB.ts
node_modulesmoduleB.tsx
node_modulesmoduleB.d.ts
node_modulesmoduleBpackage.json (假如指定了”types”屬性)
node_modulesmoduleBindex.ts
node_modulesmoduleBindex.tsx
node_modulesmoduleBindex.d.ts
“`
4) esModuleInterop
esModuleInterop為true時,表明支持採用import d from ‘cjs’的方式引入monjs包。當monjs模塊幻化為esm時,會提升 __importStar 和 _足球球版_importDefault 想法來處置幻化疑問。
示例:
cjs為monjs模塊,代碼如下:
“`
module.exports = { name ‘cjs’ };
“`
另有一個模塊以esm方式引用了cjs模塊,代碼如下:
“`
import cjsDefault from ‘cjs’;
import * as cjsStar from ‘cjs’;
console.log(‘cjsDefault =’, cjsDefault);
console.log(‘cjsStar =’, cjsStar);
“`
輸出結局為:
“`
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.hasOnProperty.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″時,默認引入[“DOM”,”ES5″,”ScriptHost”];target為”ES6″時,默認引入[“DOM”,”ES6″,”DOM.Iterable”,”ScriptHost”]。由于本示例TypeScript是用于辦事端的,不需求採用DOM和ScriptHost,所以lib設為[“ES6”]。
6) outDir
輸出目次,編譯生成的js文件所輸出的根目次,默投降出到ts文件地點的目次。
7) sourceMap
是否生成source map文件,通過採用source map 可以在過錯信息中可以顯示源碼位置。
要想依據source map 顯示過錯信息源碼位置,還需求在進口文件引入source-map-support 模塊,如下:
“`
import ‘source-map-supportregister’;
“`
三、 劇本號召
進口文件為srcserver.ts,package.json中的scripts部署如下:
– package.json
“`
{
“scripts” {
“dev” “nodemon –atch src -e ts,tsx –exec ts-node srcserver.ts”,
“build” “tsc”,
“start” “node distserver.js”
},
…
}
“`
1. 執行 npm run dev 號召可以發動開闢環境,當src下的文件被改動后會主動從頭發動辦事。
2. 執行 npm run build 號召會進行編譯,由于tsconfig.json中 outDir 指定輸出目次為dist,編譯后的js文件將出輸出到dist目次。
3. 執行 npm run start 號召可以發動利用,發動前需求執行 npm run build 進行編譯。
四、 自定義類型
TypeScript 會主動從 node_modulestypes 目次獲取模塊的類型定義,引用的模塊都需求安裝對應類型庫,如:
“`
npm install typeskoa –save
“`
安裝后,會在node_modulestypes 目次下找到koa 文件夾,該文件夾下有koa關連的類型定義文件。當引用koa模塊時會主動引入node_modules 和 node_modulestypes下的 koa 包。假如某個模塊沒有類型庫或者對某個模塊進行了開拓需求改動類型定義,這時需求引入自定義的類型。
示例:給koa提升bodyparser中間件
1. 建置typeRoots
– tsconfig.json
“`
{
“pilerOptions” {
…
類型宣示文件地點目次
“typeRoots” [“.node_modulestypes”, “.srctypes”],
},
“include” [
“src***”
],
“exclude” [
“node_modules”,
“***.spec.ts”
]
}
“`
srctypes是寄存自定義類型的目次,本示例中srctypes目次已被include涵蓋,假如自定義的類型目次未被include涵蓋還需求在include中增添該目次。
2. 編寫類型定義文件
– srctypeskoaindex.d.ts
“`
import * as Koa from “koa”;
declare module “koa” {
interface Request {
body? object;
raBody string;
}
}
“`
這里給koa的request對象提升body和raBody兩個屬性,差別用運彩虛擬投注ptt于寄存請願體的json對象和原始字符串。
3. 編寫 jsonBodyParser 插件
– srcmdlearejsonBodyParser.ts
“`
import Koa from “koa”;
function getRaBody(ctx Koa.Context) Promise {
return ne 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內容失敗’, e);
reject(e);
}
})
}
export default function jsonBodyParser () Koa.Mdleare {
return async(ctx Koa.Context, next Koa.Next) = {
const raBody string = aait getRaBody(ctx);
const request Koa.Request = ctx.request;
request.raBody = raBody;
if (raBody) {
try {
request.body = JSON.parse(raBody);
} catch (e) {
request.body = {};
}
}
aait next();
};
}
“`
jsonBodyParser()會回去一個koa中間件,這個中間件將獲取請願體的內容,將原始內容字符串賦值到ctx.request.raBody,將請願體內容json對象賦值到ctx.request.body。由于srctypeskoaindex.d.ts自定義類型已經開拓了Koa.Request的這兩個屬性,執行npm run build號召,採用 tsc 進行編譯,可以編譯勝利。不過當執行 npm run dev 時,會提示編譯過錯,那是由於ts-node默認不會依據部署中的files、include 和 exclude 加載所有ts文件,而是從進口文件開端依據引用和依靠加載文件。最簡樸的解決設法即是在 ts-node 號召后提升 –files 參數,表明按部署的files、include 和 exclu運彩 交易驗證密碼de加載ts文件,如下:
– package.json
“`
{
“scripts” {
“dev” ” nodemon –atch src -e ts,tsx –exec ts-node –files srcserver.ts”,
}
}
“`
五、 說明
本文介紹了如何在node辦事中採用TypeScript,具體的TypeScript語法紀則上有許多關連的資料,這里就不再介紹了。本文關連的代碼已提交到GitHub以供參考,
項目地址:[sgithub.liulinspnode-server-typescript-demo]。