时间:2021-07-01 10:21:17 帮助过:6人阅读
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等强类型语言相近的体验,它可以:
使得大型项目可维护
提高效率,错误在编写代码时报错,而非编译阶段
增强代码的可读性,可以做到代码即文档
增强设计
Facebook出品的JavaScript静态类型检查工具,它可以部分引入,不需要完全重构整个项目,所以对于一个已有一定规模的项目来说,迁移成本更小,也更加可行
flow使用学习成本也相对比较低
全局安装flow命令行工具
- npm install -g flow-bin
在项目根目录,创建.flowconfig文件
安装babel插件
- npm install --save-dev babel-plugin-transform-flow-strip-types
在.babelrc文件中添加插件
- {
- "presets": [ "es2015", "react", "stage-1" ],
- "plugins": [
- "react-flow-props-to-prop-types"
- ]
- }
安装扩展(⇧⌘X):Flow Language Support
修改VS Code对JavaScript的默认配置
Code -> 首选项 -> 用户设置(⌘,)
搜索:javascript.validate.enable
修改为:"javascript.validate.enable": false
在项目中使用
在需要静态检查的文件头引入flow,如:
- /* @flow */
- function getPrice(x: number) {
- return x * 10;
- }
- getPrice('a23') // vscode 工具提示错误
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/
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']);
- })
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都是静态类型检查的优秀解决方案,能够给有类型检查需求的一定规模的项目带来实际收益。基于现有项目的情况,迁移 TypeScript 时间成本比较大,学习曲线相对陡峭,建议现有项目采用 Flow 方案,对于一些新的项目,可以采用 TypeScript
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
react 官网动画库(react-transition-group)的新写法
React-Reflux的基础介绍
以上就是关于react项目静态类型检查方案的详细内容,更多请关注Gxl网其它相关文章!