日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

javascript 迁移 typescript 实践

發(fā)布時(shí)間:2025/3/18 javascript 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javascript 迁移 typescript 实践 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

只是抱著嘗試的心態(tài)對項(xiàng)目進(jìn)行了遷移,體驗(yàn)了一番typeScript的強(qiáng)大,當(dāng)然,習(xí)慣了JavaScript的靈活,弱類型,剛用上typeScript時(shí)會很不適應(yīng),猶如懶散慣了的人被突然箍上各種枷鎖,約束。但是,從長遠(yuǎn)來看,尤其是多人協(xié)作的項(xiàng)目,還是很有必要的。

typescript的優(yōu)點(diǎn)

  • 靜態(tài)代碼檢查

可以規(guī)避一些容易被忽視,隱晦的邏輯或語法錯(cuò)誤,幫助我們寫更加健壯,安全的代碼,如下所示

function getDefaultValue (key, emphasis) {let ret;if (key === 'name') {ret = 'GuangWong';} else if(key=== 'gender') {ret = 'Man';} else if (key === 'age') {ret = 23;} else {throw new Error('Unkown key ');}if (emphasis) {ret = ret.toUpperCase();}return ret;}getDefaultValue('name'); // GuangWonggetDefaultValue('gender', true) // MANgetDefaultValue('age', true)

這是一個(gè)簡單的函數(shù),第一個(gè)參數(shù) key 用來獲得一個(gè)默認(rèn)值。第二參數(shù) emphasis 為了某些場景下要大寫強(qiáng)調(diào),只需要傳入 true 即可自動(dòng)將結(jié)果轉(zhuǎn)成大寫。

但是如果不小心將 age 的值寫成了數(shù)字字面量,如果我調(diào)用 getDefaultValue('age', true) 就會在運(yùn)行時(shí)報(bào)錯(cuò)。這個(gè)有可能是業(yè)務(wù)上線了之后才發(fā)生,直接導(dǎo)致業(yè)務(wù)不可用。

  • 提高效率,錯(cuò)誤在編寫代碼時(shí)報(bào)錯(cuò),而非編譯階段

如有一種場景,在代碼重構(gòu)遷移模塊目錄時(shí),一些模塊依賴引用路徑變更,或者是引用的模塊還沒安裝,不存在時(shí),配合vscode, 及時(shí)指出錯(cuò)誤,不用等跑一遍編譯

這種情況也適用于引用非定義變量等錯(cuò)誤

- 增強(qiáng)代碼的可讀性,可以做到代碼即文檔。

雖然代碼有注釋,但是并不是每個(gè)人都有良好的習(xí)慣

react 組件設(shè)計(jì)export interface CouponProps { coupons: CouponItemModel[]; }export interface couponState {page: number,size: number }class CouponContainer extends React.Component<CouponProps, couponState> {render() {return (<div>{this.props.coupons.map((item: CouponItemModel) => item.title)}</div>)} }使用 JS 寫的 Component,Props 和 State表現(xiàn)的并不明顯。使用 Typescript 編寫 React 組件,需要為組件定義好 Props 和 State。而這也被證明是個(gè)好的編碼方式。其可以幫助你構(gòu)建更健壯的組件,別人經(jīng)手自己的代碼時(shí)可以很清楚知道一個(gè)組件需要傳入哪些參數(shù)

- 增強(qiáng)設(shè)計(jì)

相關(guān)實(shí)踐

實(shí)踐是消弭困惑最好的方式,抱著好奇,排斥的心態(tài)還是對對項(xiàng)目進(jìn)行了遷徙

  • 項(xiàng)目目錄介紹
  • --

    如上圖所示,項(xiàng)目中所有源碼都放在src目錄中,src/client為客戶端的源碼,src/server為服務(wù)器端的代碼,dist目錄是編譯后的目錄

    2. typescript In node

    2.1.準(zhǔn)備階段
    使用npm安裝:npm install -g typescript,當(dāng)前項(xiàng)目使用了是v2.8.3

    2.2 tsconfig.json
    在項(xiàng)目的根目錄下新建立tsconfig.json文件,并編輯相關(guān)配置項(xiàng)

    {"compilerOptions": {"module": "commonjs","target": "es5","noImplicitAny": true,"sourceMap": true,"lib": ["es6", "dom"],"outDir": "dist","baseUrl": ".","jsx": "react","paths": {"*": ["node_modules/*","src/types/*"]}},"include": ["src/**/*"] }

    相關(guān)配置解析可參考tsconfig.json

    2.3 結(jié)合gulp

    var gulp = require('gulp'); var pump = require('pump'); var webpack = require('webpack'); var gutil = require('gulp-util'); var webpackDevConfig = require(__dirname + '/webpack.config.dev.js');var ts = require('gulp-typescript'); var livereload = require('gulp-livereload'); var tsProject = ts.createProject("tsconfig.json");gulp.task('compile:tsc:server', function () {return gulp.src('src/server/**/*.ts').pipe(tsProject()).pipe(gulp.dest('dist/server')); });gulp.task('compile:tsc:client', function(callback){webpack(webpackDevConfig, function(err, stats){if(err) throw new gutil.PluginError("webpack:build-js", err);gutil.log("[webpack:build-js]", stats.toString({colors: true}));callback();}); });//將任務(wù)同步執(zhí)行 var gulpSequence = require('gulp-sequence');gulp.task('copy:html', function() {return pump([gulp.src('./src/views/**/*'),gulp.dest('./dist/server/views')]) });gulp.task('compile', gulpSequence('compile:tsc:server','compile:tsc:client','copy:html' ))gulp.task('watch', ['compile'], function() {livereload.listen();gulp.watch(['./src/server/**/*.ts'], ['compile:tsc:server']);gulp.watch(['./src/client/**/*.ts'], ['compile:tsc:client']);gulp.watch(['./src/views/**/*.html'], ['copy:html']); })

    2.4 測試
    在src/server/app.ts下編寫代碼

    /// <reference path="../types/custom.d.ts" />import * as express from "express"; import * as compression from "compression"; // compresses requests import * as cookieParser from "cookie-parser"; import * as bodyParser from "body-parser"; import * as path from "path"; import * as favicon from "serve-favicon"; import * as fs from "fs";global.APP_PATH = __dirname;const programConfig = require(path.join(global.APP_PATH + "../../../config/index")); global.config = programConfig.get("config");const mainRouters = require("./routers/main");const underscore = require("underscore");global._ = underscore._;const app = express(); // parse application/x-www-form-urlencodedapp.use(bodyParser.urlencoded({ extended: false }));// parse application/json app.use(bodyParser.json());// protocal app.use(function(req: express.Request, res: express.Response, next: express.NextFunction) {app.locals.protocol = req.protocol;app.locals.host = req.headers.host;next(); });// view engine setup app.set("views", path.join(__dirname, "./views")); app.set("view engine", "jade"); app.engine("html", require("ejs-mate"));app.use(compression()); app.use(cookieParser());// resources const cacheOptions = {maxAge : "1d", };app.use("/test", express.static(path.join(__dirname, "../public"), cacheOptions));app.use("/", mainRouters);const port = process.env.PORT || programConfig.get("config").port; const server = app.listen(port, function() {console.log("App is runing");console.log("server is listening on " + port); });module.exports = app;

    2.5 遇到的問題

    • 動(dòng)態(tài)地為global添加屬性

    由于js靈活的風(fēng)格,我們經(jīng)常動(dòng)態(tài)地為某一對象添加屬性,但是typeScript是編譯型語言,基本原則是先定義再使用,所以當(dāng)我們像下面這么引用

    global.testName = '哈哈';

    便會出現(xiàn)這樣的錯(cuò)誤

    類型“Global”上不存在屬性“testName”

    解決方法

    (1)將global強(qiáng)制轉(zhuǎn)化為any類型(<any>global).testName = '哈哈'(2)擴(kuò)展原有的對象global.prototy.testName = '哈哈哈'(3)使用.d.ts文件 declare namespace NodeJS {export interface Global {testName: string;} }

    網(wǎng)上很多方法是直接添加一個(gè).d.ts文件即可,但是親測無效,需要在引用文件引入該文件,如本項(xiàng)目在app.ts文件中引入了

    /// <reference path="../types/custom.d.ts" />

    集成單元測試

    項(xiàng)目用的測試框架是 jest + enzyme

  • 安裝 jest
  • npm i -D jest @types/jest
    npm i -D ts-jest

  • 安裝 enzyme
  • npm i -D enzyme @types/enzyme

  • 配置 jest.config.js 文件
  • module.exports = {collectCoverage: true,moduleFileExtensions: ['ts','js','tsx'],transform: {"^.+\\.tsx?$": "ts-jest",},testMatch: ['**/test/**/*.test.(ts|js|tsx)'],testEnvironment: 'node' };

    4.編寫測試用例 coupon.test.tsx

    import * as React from 'react'; import { shallow, configure } from 'enzyme'; import * as Adapter from 'enzyme-adapter-react-16';configure({ adapter: new Adapter()})test('Jest-React-TypeScript 嘗試運(yùn)行', () => {const renderer = shallow(<div>hello world</div>)expect(renderer.text()).toEqual('hello world') })

    總結(jié)

    以上是生活随笔為你收集整理的javascript 迁移 typescript 实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。