最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

关于react项目静态类型检查方案

来源:动视网 责编:小采 时间:2020-11-27 19:34:02
文档

关于react项目静态类型检查方案

关于react项目静态类型检查方案:这篇文章主要介绍了关于react项目静态类型检查方案,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下为什么需要引入类型检查JS作为一个弱类型语言,具有很大的灵活性,但是它的优点也是它的缺点,它很容易让我们忽视一些隐晦的逻辑,语法错误
推荐度:
导读关于react项目静态类型检查方案:这篇文章主要介绍了关于react项目静态类型检查方案,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下为什么需要引入类型检查JS作为一个弱类型语言,具有很大的灵活性,但是它的优点也是它的缺点,它很容易让我们忽视一些隐晦的逻辑,语法错误
 这篇文章主要介绍了关于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命令行工具

    npm install -g flow-bin
    1. 在项目根目录,创建.flowconfig文件

    2. 安装babel插件

    npm install --save-dev babel-plugin-transform-flow-strip-types
    1. 在.babelrc文件中添加插件

    {
     "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. 在项目中使用

    在需要静态检查的文件头引入flow,如:

    /* @flow */
    function getPrice(x: number) {
     return x * 10;
    }
    getPrice('a23') // vscode 工具提示错误

    采用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, couponState> {
    }

    上述组件我们可以清晰地知道一个组件有哪些属性,哪些方法,哪些属性是必传的,哪些是可选的,一目了然,真正做到了代码即文档

    关于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文件
    declare namespace NodeJS {
     
     export interface Global {
     testName: string;
     }
    }

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

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

    Flow 与 TypeScript简单对比

    总结

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

    文档

    关于react项目静态类型检查方案

    关于react项目静态类型检查方案:这篇文章主要介绍了关于react项目静态类型检查方案,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下为什么需要引入类型检查JS作为一个弱类型语言,具有很大的灵活性,但是它的优点也是它的缺点,它很容易让我们忽视一些隐晦的逻辑,语法错误
    推荐度:
    标签: 检查 静态 项目
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top