- Notifications
You must be signed in to change notification settings - Fork790
Compile Time Type Checking
WARNING: This page documents on-going development on the ClojureScript master branch.
ClojureScript can easily leverage Google Closure for compile time type checking. This is done simply via ClojureScript docstrings which are compiled intoJSDoc style comment blocks. Google Closure supports many useful kinds oftype annotation. For example you can write a function that takes non-nullable Object.
(defnfoo"@param {!Object} x" [x]x)
If Closure can infer that some invoke may pass null, this will result in a compile time type error.
Type checking can be enabled for:simple
or:advanced
optimization builds:
(require '[cljs.build.api:as b])(b/build"src" {:main 'my.ns:output-to"app.js":optimizations:simple:verbosetrue:closure-warnings {:check-types:error;; << ADD THIS:undefined-names:off:externs-validation:off:missing-properties:off}})(System/exit0)
The other:closure-warnings
options here are to disable noisier checks that are less relevant for ClojureScript projects.
ClojureScript supports unqualified type names in@param
and@return
annotations. These will automatically be expanded based on the vars currently in scope.
(defnbar"@param {!IVector} v @return {!IMap}" [v] {})
BothIVector
andIMap
will be resolved tocljs.core
where they are defined.
Programs written around concrete types are not idiomatic. ClojureScript itself is written in terms of a rich set of protocols. Therefore it is important to support type checking on protocols rather than particular types.
Protocols all emit an@interface
annotation. Anydeftype
ordefrecord
that implements some protocol will have its JSDoc annotation extended with@implements
for that protocol.
It would be interesting to generate@param
and@return
automatically. For example the following:
(defnfoo [x y] {:pre [(map? x) (or (number? y) (string? y))]:post [(vector? %)]}; ... )
Could be made equivalent to:
(defnfoo"@param {!IMap} x @param {(number|string)} y @return {!IVector}" [x y]; ... )
The following is a common idiom:
(if-let [v (:foo m)] (non-nullable-fn v))
In master this would still generate a type error since Closure doesn't know thatif-let
preventsv
from ever beingnull
.
We could changeif-let
to emit a(goog.asserts/assert v)
as the first statement of the successful branch. This would inform the type checker thatv
can never benull
.
- Rationale
- Quick Start
- Differences from Clojure
- [Usage of Google Closure](Google Closure)