• 编译期类型检查 in ClojureScript


    前言

     话说"动态类型一时爽,代码重构火葬场",虽然有很多不同的意见(请参考),但我们看到势头强劲的TypeScript和Flow.js,也能感知到静态类型在某程度上能帮助我们写出更健壮的代码(当然要基于充分的单元测试上啦)。
     ClojureScript与JavaScript一样采取动态类型,但由于需要通过Google Closure Compiler编译后才能运行,因此我们可以如同JS那样借助GCC的注解来引入编译时类型检查,达到同样静态类型的效果。

    配置项目设置

    GCC的编译时类型检查仅当optimizationssimpleadvanced时有效。我们以:cljsbuild下的dev配置为例

    :cljsbuild 
      {:builds
       [{:id "dev"
         :main type-check.core
         :output-to "resouces/public/js/type_check.js"
         :optimizations :simple
         :source-map "resources/public/js/type_check.js.map"
         :closure-warnings            ;; 设置GCC编译时类型检查
           {:check-types :warning     ;; 务必设置为warning
            :undefined-names :off     ;; 屏蔽goog库的异常信息
            :externs-validation :off  ;; 屏蔽goog库的异常信息
            :missing-properties :off  ;; 屏蔽goog库的异常信息
            }}]}
    

    请注意,:check-types必须设置为:warning,若设置为:error时,就会报Math.imul引发的JSC_DUP_VAR_DECLARATION_TYPE_MISMATCH异常,导致项目其他代码均不能被编译。希望大神指点迷津~~

    注解语法

    首先GCC用到的注解语法仅为JSDoc的子集,所以直接看GCC的注解即可,而ClojureScript一般就用如下几个

    @private {Type}
    标识私有成员,且该成员的数据类型
    
    @type {Type}
    标识成员的数据类型
    
    @param {Type} varname Description
    标识函数的型参的数据类型,参数名和描述
    
    @return {Type} Description
    标识函数返回值的数据类型和描述
    
    @throws {Type}
    标识函数可能抛出异常类型
    

    接下来就是重点了,我们写了这么多还不就是想引入数据的类型描述吗?那关键就是上述代码中Type到底应该怎么写了!
    1.标量类型number,string,boolean,null,undefined
    注意
    一、标量类型默认表示变量或参数的实际值为不可为null(non-nullable)。若要标识为可为null(nullable),那么只需前置一个问号?即可(?number,?string
    2.对象类型Object,Function,Number,String,Boolean,Date和其他Cljs或自定义的对象类型。
    注意
    一、对于非全限定的对象类型,会自动展开为当前命名空间的类型(如当前命名空间为my-proj.core,那么MyArray会展开为my-proj.core/MyArray
    二、对象类型默认表示变量或参数的实际值可为null(nullable)。若要标识为不可为null(non-nullable),那么只需前置一个感叹号!即可(如!Object,!Date等)
    3.组合类型,如(number|string),即是实际值可为数字也可为字符串。
    4.集合/字典,Array<Type>表示为数组类型且其元素类型可以继续递归下去,Object<Type>表示为对象类型且键类型为Type,Object<Type1,Type2表示为对象类型且键类型为Type1而值类型为Type2
    5.函数类型
    function(Type1,Type2),表示函数含数据类型为Type1和Type2两个形参。
    function(Type1,Type2):Type3,表示函数含数据类型为Type1和Type2两个形参,且返回值类型为Type3。
    function(...Type),表示函数含数据类型为Type的可变形参,注意可变形参必须作为最后一个形参出现。
    function(Type=),表示函数含可选的数据类型为Type的形参,注意可选形参后不能声明必填的形参。
    注意注意!

    1. 形参和逗号间千万不要留空格,否则编译时会报警告的哦!
    2. Type为function()时不能在声明返回值类型,否则编译时辉报警告!
    @param {function(*,function(*):number)} 是不允许的
    @param {function(*,function(*))}        只能这样写啦
    

    6.什么类型都可以,*

    实例

    1.封装chrome.runtime.onMessage玩玩

    (defn on-msg
      "@param {function(*,window.MessageSend,function(*))} handler
       @return {null}"
      [handler]
      (let [this (.. js/chrome -runtime -onMessage)]
        (.addListener this
                      (fn [a b c]
                        (handler a b c)
                        true))))
    

    注意:window.MessageSend既不是GCC内置的类型也不是我们自定义类型,而是外部定义的数据类型,因此我们需要添加externs文件让GCC识别。
    因此得到的配置如下

    :cljsbuild
      {:builds
       [{:id "dev"
         :main type-check.core
         :output-to "resouces/public/js/type_check.js"
         :optimizations :simple
         :source-map "resources/public/js/type_check.js.map"
         :externs ["externs/chrome.js" "externs/chrome_extensions.js"]
         :closure-warnings            ;; 设置GCC编译时类型检查
           {:check-types :warning     ;; 务必设置为warning
            :undefined-names :off     ;; 屏蔽goog库的异常信息
            :externs-validation :off  ;; 屏蔽goog库的异常信息
            :missing-properties :off  ;; 屏蔽goog库的异常信息
            }}]}
    

    总结

    如官网所讲,这部分的内容仍在发展阶段,所以还有很多不完善的地方。不过也不影响我们现在就开始使用,因此良好的代码注释从来都需要的!
    尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/7625414.html _肥仔John

    参考

    https://clojurescript.org/reference/compile-time-type-checking
    https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler
    https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System
    https://github.com/google/closure-compiler/wiki/Warnings

  • 相关阅读:
    在Hibernate中不区分大小写查询
    Windows下如何查看某个端口被谁占用
    swing限制文本框只能输入数字和大写字母
    VC6命令⾏编译配置
    springboot获取application.yml的信息
    VisualStudio 2019 离线安VisualStudio 2019 离线安装包 | 完整负载.独立负载.单个组件装包 | 完整负载.独立负载.单个组件
    java根据输入的文件路径和文件名,web服务器返回一个输出流
    找不到或无法加载主类
    JTable表格关联TableRowSorter类实现排序功能
    正则转换驼峰和下划线
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/7625414.html
Copyright © 2020-2023  润新知