We want type checking for Clojurescript.
[Design] New Host, New Types
What is a deftype in CLJS? eg. Is it a Class with fields? Is it just a structural type?
[Design, Theory] Built on Protocols
The types in TC are fairly sophisticated for combining interfaces and protocols. We have an `Extends` constructor that takes positive and negative information on things it can extend.
eg. `(Extends [(Seqable t)] :without [Number])` is a type that implements `(Seqable t)` and explicitly does not implement `Number`.
ClojureScript brings an interesting challenge with its core protocols, because there is no explicit inheritance. In Clojure, the corresponding solution is to use interfaces with inheritance. eg. `(IPersistentMap t)` is a `(Seqable t)` and `(IPersistentCollection t)` explicitly because the interface extends both these types.
In CLJS, `IMap` is a protocol. There is no explicit inheritance of `Seqable` or `ICollection`. This seems to imply that we need quite large type aliases like this one:
(def-alias Vec (TFn [[x :variance :covariant]] (Extends [(Seqable x) (IVector x) (IStack x) (ICollection x) (IAssociative Int x) ...])))
This complicates even further a problem I have in Typed Clojure.
Consider code like this:
(let [x (ann-form  (Vec Any)) _ (assert (every? number? x)) ...] ...)
What do we update the type of x to? `(Seqable Number)`? `(ICollection Number)`? Some combination? Ideally we'd want the equivalent of `(Vec Number)`, but this seems pretty hard to achieve.
This kind of updating of an expressive collection type seems like it might be useful, but maybe it's just enough to update the `Seqable` or `ICollection` portion of the type?
[Implementation] High-level, write in CLJ vs CLJS
For high-level implementation, we have two options:
- Rewrite TC in CLJS
- Reuse the type infrastructure of TC and provide "type-checking as a service", callable from a CLJS REPL
Option 1 is a lot more effort. We probably need a full CLJS compiler available anyway, which probably also implies Java is available at development time.
Option 2 is probably the better way to go.