• React Native填坑之旅--Flow篇


    flow不是React Native必会的技能,但是作为正式的产品开发优势很有必要掌握的技能之一。所以,算是RN填坑之旅系列的番外篇。

    Flow是一个静态的检查类型检查工具,设计之初的目的就是为了可以发现JavaScript脚本里不容易被发现的错误。在js开发的过程中,总会遇到一些问题。小的还可以,比如用alert或者console等输出一些信息可以debug,并解决。但是如果项目比较大的时候,这些手法只能起到一定的辅助作用。更有甚者,有些问题不运行到那段代码,根本不会发现错误。Facebook的兄弟们就是为了解决这个问题,于是开发了flow。

    首先,跳转的你的项目目录下。然后就开始正文了。

    安装&配置

    Flow就从安装开始。

    npm install --save-dev flow-bin
    • 1

    创建配置文件。

    touch .flowconfig
    • 1

    先不管空白的.flowconfig配置文件。在package.json文件里flow脚本。
    your project/package.json

    1. "scripts": {
    2. "flow": "flow; test $? -eq 0 -o $? -eq 2",
    3. },
    • 1

    然后给需要flow检查的文件里加上//@flow或者/*@flow*/。然后就可以检查了。(也可以在命令中加上–all, 这样就会检查所有文件)。

    在根目录下运行命令:

    npm run flow
    • 1

    用Flow检查

    现在就把flow用起来。Flow绝不是上面几个命令而已,而是一套类型体系。下面通过一个例子来了解一下flow和flow的类型体系。

    1. export default function(state = initialState, action) {
    2. switch (action.type) {
    3. case actionTypes.TRACKS_SET:
    4. return setTracks(state, action);
    5. case actionTypes.TRACK_PLAY:
    6. return setPlay(state, action);
    7. }
    8. return state;
    9. }
    10. function setTracks(state, action) {
    11. const { tracks } = action;
    12. return { ...state, tracks };
    13. }
    • 1

    第一次检查会出很多的错,因为上面的写法没有按照flow的定义添加类型声明。下面来添加类型声明。

    1. // @flow
    2. import * as actionTypes from './actionTypes';
    3. const initialState = {
    4. tracks: [],
    5. activeTrack: null
    6. };
    7. export default function(state = initialState, action) {
    8. switch (action.type) {
    9. case actionTypes.TRACKS_SET:
    10. return setTracks(state, action);
    11. case actionTypes.TRACK_PLAY:
    12. return setPlay(state, action);
    13. }
    14. return state;
    15. }
    16. function setTracks(state, action) {
    17. const { tracks } = action;
    18. return { ...state, tracks };
    19. }
    20. function setPlay(state, action) {
    21. const { track } = action;
    22. return { ...state, activeTrack: track };
    23. }
    • 1

    运行命令check命令之后会显示错误的内容:

    1. test/track.js:10                                                                                        
    2.  10: export default function(state = initialState, action) {                                            
    3.                              ^^^^^ parameter `state`. Missing annotation                                
    4.                                                                                                         
    5. test/track.js:10                                                                                        
    6.  10: export default function(state = initialState, action) {                                            
    7.                                                    ^^^^^^ parameter `action`. Missing annotation 
    • 1

    flow的错误提示我们,需要给出方法的参数类型。

    Flow: Any类型

    修改代码:

    1. export default function(state: any = initialState, action: any) {
    2. switch (action.type) {
    3. case actionTypes.TRACKS_SET:
    4. return setTracks(state, action);
    5. case actionTypes.TRACK_PLAY:
    6. return setPlay(state, action);
    7. }
    8. return state;
    9. }
    • 1

    这样修改之后就没有什么错误提示了。我们给参数指定了any类型。这个类型是所有类型的父类型,也是所有类型的子类型。所以,任何类型都可以用any代表了。但是这样并不能发挥类型检查的优势。

    Flow:类型别名

    使用flow的类型别名可以解决上面的问题。输出的默认方法的第一个参数其实是一个State类型的实例。在本例中使用的State是一个对象,其中tracks是一个数组,activeTrack是一个可以为空的对象。为State定义一个类型别名:

    1. type State = {
    2. tracks: Array<any>,
    3. activeTrack: ?any
    4. };
    5. const initialState = {
    6. tracks: [],
    7. activeTrack: null
    8. };
    • 1

    正好之前定义的initialState就是State类型的一个实例。同理,我们也可以为initialStateactiveTrack定义一个类型。

    1. type Track = {
    2. //这里给出定义
    3. }
    • 1

    然后State类型就是这样的了:

    1. type Track = {
    2. //这里给出定义
    3. }
    4. type State = {
    5. tracks: Array<any>,
    6. activeTrack: ?Track
    7. };
    • 1

    注意,这里我们用到了一个特殊的类型:Maybe Type(可能类型或者可空类型)。这个类型的定义方式就是在类型的前面放一个问号。

    下面也为两个方法setTrackssetPlay定义返回的类型,并应用到对应的方法上:

    1. // @flow
    2. import * as actionTypes from './actionTypes';
    3. type Track = {
    4. trackName: string
    5. };
    6. type State = {
    7. tracks: Array<any>,
    8. activeTrack: ?Track
    9. };
    10. type SetTrackAction = {
    11. type: string,
    12. tracks: Array<Track>
    13. };
    14. type PlayTrackAction = {
    15. type: string,
    16. track: Track
    17. };
    18. const initialState = {
    19. tracks: [],
    20. activeTrack: null
    21. };
    22. export function setTracks(tracks: Array<Track>): SetTrackAction {
    23. return {
    24. type: actionTypes.TRACKS_SET,
    25. tracks
    26. };
    27. }
    28. export function setPlay(track: Track): PlayTrackAction {
    29. return {
    30. type: actionTypes.TRACK_PLAY,
    31. track: track
    32. };
    33. }
    • 1

    Flow: Type Union

    SetTrackActionPlayTrackAction可以使用Type Union的方式统一起来:

    type Action = SetTrackAction | PlayTrackAction;
    • 1

    修改代码:

    1. export function setTracks(tracks: Array): Action {
    2. return {
    3. type: actionTypes.TRACKS_SET,
    4. tracks
    5. };
    6. }
    7. export function setPlay(track: Track): Action {
    8. return {
    9. type: actionTypes.TRACK_PLAY,
    10. track: track
    11. };
    12. }
    • 1

    Flow: 模块处理

    这里主要说明一种情况。如果引入的另外一个模块和本模块定义了一个同名的类型别名,但是里面包含的内容不同,那么Flow会检查出来并报错。
    比如,现在我们的模块里有了Track这个类型,是这样的:

    1. type Track = {
    2. trackCode: string
    3. };
    • 1

    如果在引入的actionTypes.js文件中也包含一个Track类型,但是定义的有些不同:

    1. type Track = {
    2. trackCode: number
    3. };
    • 1

    两个Track的不同就在于trackCode的类型,一个是string,一个是number

    运行flow之后就会显示出来具体的报错:

    1. test/actionTypes.js:13                                                                                  
    2.  13:            trackCode: 123                                                                          
    3.                            ^^^ number. This type is incompatible with the expected return type of       
    4.   5:   trackCode: string                                                                                
    5.                   ^^^^^^ string  
    • 1

    Flow: 声明类型

    上面的问题解决起来很简单,把两个类型的定义保持一致就可以。但是,我们不可能在任何一个需要Track类型的文件中都定义一个一模一样的类型。

    Flow提供了一种特殊的类型声明方式,可以一次声明到处使用。

    .flowconfig文件中的[lib]下添加如下内容。如果这个文件为空的话,运行flow init命令。

    1. [libs]
    2. decls
    • 1

    在根目录下:

    1. mkdir decls
    2. cd decls
    3. touch flowTypes.js
    • 1

    在文件flowType.js中:

    1. declare type Track = {
    2. trackCode: string;
    3. };
    • 1

    把其他的Track类型声明全部都删掉,然后运行命令:

    npm run flow
    • 1

    最后

    Flow对React的支持与上文所述的基本上大同小异。各位可以移步官网细看。

  • 相关阅读:
    oauth2 授权模式 - 第三方登录
    72-Java的选择排序、二分查找、Lambda表达式
    webgoat-Broken Access ControlI 访问控制失效
    JavaWeb--Maven
    Python——异常
    自定义表单、自定义流程、自定义页面、自定义报表应用开发平台
    想打造私域流量帝国?先解决这4个难题!
    DS森林叶子编码/森林转二叉树 【数据结构】
    RK3588 Android13 TvSetting 中性能浮窗RAM显示bug
    【python源码解析】深入 Pandas BlockManager 的数据结构和初始化过程
  • 原文地址:https://blog.csdn.net/m0_71272694/article/details/127865396