首頁  >  文章  >  web前端  >  關於react專案靜態類型檢查方案

關於react專案靜態類型檢查方案

不言
不言原創
2018-07-09 11:02:481678瀏覽

這篇文章主要介紹了關於react專案靜態類型檢查方案,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

為什麼需要引入類型檢查

JS作為一個弱類型語言,具有很大的靈活性,但是它的優點也是它的缺點,它很容易讓我們忽略一些隱晦的邏輯,語法錯誤或資料類型錯誤,在編譯期甚至運行時看起來都不會報錯,但可能會發生各種奇怪的和難以解決的bug。

function getPrice(x) {
  return x * 10;
}
getPrice('a23') // NaN
function getDefaultValue (key, emphasis) {
    let ret;
    if (key === 'name') {
      ret = 'GuangWong';
    } else if(key=== 'gender') {
      ret = 'Man';
    }else if(key ==='age'){
      ret = 18;
    } else {
       throw new Error('Unkown key ');
    }
    if (emphasis) {
      ret = ret.toUpperCase();
    }
    return ret;
  }
  
  getDefaultValue('name'); // GuangWong
  getDefaultValue('gender', true) // MAN
  getDefaultValue('age', true)

這是一個簡單的函數,第一個參數 key 用來得到一個預設值。第二參數 emphasis 為了某些場景下要大寫強調,只需要傳入 true 即可自動將結果轉成大寫。

但如果不小心將 age 的值寫成了數字字面量,如果我呼叫 getDefaultValue('age', true) 就會在執行時報錯。這個有可能是業務上線了之後才發生,直接導致業務不可用

除此以外,在工作中,我們也經常遇到過對像上的一個屬性在n個模組之間傳遞之後變成了undefined。以上是程式碼健壯性的問題,工作中比較頭痛的另一個問題是協作性問題:如何讓一個別人提供的方法產出一個一目了然的文檔?因為一個專案總是會牽涉到多人協作:同學A 寫了函數a(),而同學B 在呼叫函數a() 的時候得一直擼著API 文件才能知道a() 需要什麼參數,會回傳什麼參數。

而同學A 後續又改動了函數a(),但是卻忘了更新文檔,這時候新接手專案的同學C 看著API 文檔和函數a() 一臉懵逼,問題浮現水面:團隊協作中,提供的介面如何描述自身?

這其中涉及的問題有:

1.介面如何描述自己的參數和回傳值?
2.介面參數和回傳值在無數需求迭代中改變了多次,而這個 API 對應的文檔該如3.何更新?
4.資料格式如何描述?

為了解決上述諸多痛點,我們需要引入類型檢查機制,所謂類型檢查,就是在編譯期儘早發現(由類型錯誤引起的)bug,又不影響程式碼運行(不需要運行時動態檢查類型),使編寫js具有和編寫Java等強類型語言相近的體驗,它可以:

  • #使得大型專案可維護

  • ##提高效率,錯誤在寫程式碼時報錯,而非編譯階段

  • 增強程式碼的可讀性,可以做到程式碼即文檔

  • #增強設計

採用Flow

Facebook出品的JavaScript靜態類型檢查工具,它可以部分引入,不需要完全重構整個項目,所以對於一個已有一定規模的專案來說,遷移成本較小,也比較可行

flow使用學習成本也相對比較低

  1. 全域安裝flow指令列工具

  2. npm install -g flow-bin
  1. 在專案根目錄,建立.flowconfig檔

  2. 安裝babel插件

  3. npm install --save-dev babel-plugin-transform-flow-strip-types
  1. 在.babelrc檔案中加入外掛程式

  2. {
      "presets": [ "es2015", "react", "stage-1" ],
      "plugins": [
            "react-flow-props-to-prop-types"
      ]
    }
  1. 安裝擴充功能(⇧⌘X):Flow Language Support

  2. 修改VS Code對JavaScript的預設配置

Code -> 首選項-> 使用者設定(⌘,)

搜尋:javascript. validate.enable
修改為:"javascript.validate.enable": false

  1. 在專案中使用

  2. ##在需要靜態檢查的檔案頭引入flow,如:
/* @flow */
function getPrice(x: number) {
  return x * 10;
}
getPrice('a23') // vscode 工具提示错误

關於react專案靜態類型檢查方案採用typescript

TypeScript 被稱為JavaScript 的超集,是微軟公司推出的靜態程式碼檢查的方案,在JavaScript 上做了一層封裝,封裝出TypeScript 的特性,當然最終程式碼可以編譯為JavaScript

1.靜態型別

let num: number;
num = 'likely';
    
[ts] 不能将类型“"likely"”分配给类型“number”。
let num: number

2.函數表達式


## js寫法

export const fetch = function (url, params, user) {
  // dosomething

  return http(options).then(data => {
    return data
  }).catch(err => {
    return err
  })
}

以上下方是一個JavaScript 的函數,所以不看方法內的寫法我們完全不知道這個API 會有哪些坑。
    export const fetch = function (url: string | object, params?: any, user?: User): Promise<object | Error> {
      // dosomething
    
      return http(options).then(data => {
        return data
      }).catch(err => {
        return err
      })
    }
  • 上述TypeScript 包含了許多訊息,讓我們很方便地知道該函數怎麼呼叫

  • url 可能是string 或object 類型

  • #params 是可以不傳的,也可以傳遞任何型別

  • user 要求是User 類型的,當然也是可以不傳

回傳了一個Promise,Promise 的求值結果可能是object,也有可能是Error

3.元件###
export interface CouponProps { 
  coupons: CouponItemModel[]; 
}

export interface couponState {
    coupons: CouponItemModel[],
    page: number,
    size: number,
    state: number,  //可用优惠券
    hasMore: boolean,
    isLoading: boolean,
    loadedError: boolean,
}


class CouponContainer extends React.Component<couponprops> {
}</couponprops>
###上述元件我們可以清楚知道一個元件有哪些屬性,哪些方法,哪些屬性是必傳的,哪些是可選的,一目了然,真正做到了程式碼即文檔###

关于typescript还有很多其他特点,如类,接口,泛型等,具体可参考官方文档
https://www.typescriptlang.org/

项目迁移typescript

1.node
(1)使用npm安装:npm install -g typescript,当前项目使用了是v2.8.3
(2)2.2 tsconfig.json

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

(3)将.js文件改为.ts
(4)结合 gulp 进行实时编译

var gulp = require('gulp');
var pump = require('pump');
var webpack = require('webpack');

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'));
});
//将任务同步执行
var gulpSequence = require('gulp-sequence');
gulp.task('compile', gulpSequence(
  'compile:tsc:server',
))


gulp.task('watch', ['compile'], function() {
  livereload.listen();

  gulp.watch(['./src/server/**/*.ts'], ['compile:tsc:server']);
})
  1. react

可在 webpack 配置文件添加规则

{ 
    test: /\.tsx?$/, 
    enforce: 'pre',
    use: [
        {
            loader: "ts-loader"
        }
    ]
 },

3.遇到的问题
遇到的问题

  • 动态地为global添加属性

由于js灵活的风格,我们经常动态地为某一对象添加属性,但是typeScript是编译型语言,基本原则是先定义再使用,所以当我们像下面这么引用

global.testName = '哈哈';

便会出现这样的错误

类型“Global”上不存在属性“testName”

解决方法

(1)将global强制转化为any类型

 (<any>global).testName = '哈哈'
    
(2)扩展原有的对象

  global.prototy.testName = '哈哈哈'

(3)使用.d.ts文件</any>
declare namespace NodeJS {
 
  export interface Global {
    testName: string;
  }
}

网上很多方法是直接添加一个.d.ts文件即可,但是亲测无效,需要在引用文件引入该文件,如本项目在app.ts文件中引入了

/// <reference></reference>

Flow 与 TypeScript简单对比

關於react專案靜態類型檢查方案

总结

Flow或者TypeScript都是静态类型检查的优秀解决方案,能够给有类型检查需求的一定规模的项目带来实际收益。基于现有项目的情况,迁移 TypeScript 时间成本比较大,学习曲线相对陡峭,建议现有项目采用 Flow 方案,对于一些新的项目,可以采用 TypeScript

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

react 官网动画库(react-transition-group)的新写法

React-Reflux的基础介绍

以上是關於react專案靜態類型檢查方案的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn