编译期类型检查 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的形参,注意可选形参后不能声明必填的形参。 注意注意!

形参和逗号间千万不要留空格,否则编译时会报警告的哦!

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库的异常信息
        }}]}

总结

如官网所讲,这部分的内容仍在发展阶段,所以还有很多不完善的地方。不过也不影响我们现在就开始使用,因此良好的代码注释从来都需要的!

参考

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏debugeeker的专栏

《coredump问题原理探究》Linux x86版3.4节栈布局之函数参数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

751
来自专栏阿杜的世界

【译】Java 8的新特性—终极版1. 简介2. Java语言的新特性3. Java编译器的新特性4. Java官方库的新特性5. 新的Java工具6. JVM的新特性7. 结论8. 参考资料

前言: Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级。在Java Code Geeks上已经有很多介绍Java 8新特性的文章,...

1174
来自专栏10km的专栏

java nio:Files.isSameFile判断两个路径(Path)是否相等

不论在windows还是linux下,仅凭字符串比较判断两个文件路径是否相等是不靠谱的。因为有link,Disk map等技术的存在,两个不同的路径有可能指向同...

2246
来自专栏程序猿DD

JDK 1.5 - 1.8 各版本的新特性总结

此文章意在借鉴前人经验,留作日后查看。如有侵犯,实属无意。我以后会注意,谢谢博友的提醒。也愿各大博友们能够共同学习和努力。

7216
来自专栏IMWeb前端团队

代码写了那么多,你搞明白yield是个啥没?

本文作者:IMWeb 否子戈 原文出处:IMWeb社区 未经同意,禁止转载 ES6真是颠覆JavaScript的东西,随便翻一个新特性出来,就让自以为...

2189
来自专栏ImportSource

Java8真不用再搞循环了?

Java8以后真的不用循环了?真的不用了? 好吧,本文分享的内容是java8之前和java8之后一些代码的不同写法,我们会先介绍java8之前和java8之后不...

2.5K11
来自专栏小樱的经验随笔

【Java学习笔记之二十八】深入了解Java8新特性

前言: Java 8 已经发布很久了,很多报道表明java 8 是一次重大的版本升级。在Java Code Geeks上已经有很多介绍Java 8新特性的文章,...

3687
来自专栏搜云库

BTA 常问的 Java基础40道常见面试题及详细答案

最近看到网上流传着,各种面试经验及面试题,往往都是一大堆技术题目贴上去,而没有答案。

6016
来自专栏技术/开源

从C#到TypeScript - Generator

从C#到TypeScript - Generator 上篇讲了Promise,Promise的执行需要不停的调用then,虽然比callback要好些,但也显得...

2528
来自专栏pangguoming

Java编程最差实践(常见编程错误典范)

转载自  http://macrochen.iteye.com/blog/1393502

872

扫码关注云+社区

领取腾讯云代金券