clojurescriptclojurescript-javascript-interop

Clojurscript: extend a Javascript class


I'm trying to use a particular JavaScript framework which requires extending a base class to use it for application.

Basically I want to do the following as idiomatic ClojureScript.

class Foo extends Bar {
  constructor() { super("data") }
  method1(args) { /* do stuff */ }
}

I tried

(defn foo
  []
  (reify
    js/Bar
    (constructor [this] (super this "data"))
    (method1 [this args] )))

Which would work if I'd create a new class from Object, but as shadow-cljs correctly complains, "Symbol js/Bar is not a protocol". Also, I don't want to add methods but create a subclass that inherits somemethods and overloads others.

I thought about using proxy, but "core/proxy is not defined".

Of course I could create an instance of Bar and set! new methods, but that feels like giving up and using an inferior language.


Solution

  • Please see answer below for more current solution!

    CLJS has no built-in support for class ... extends ....

    You can hack it together yourself with a bit of boilerplate, which you could generate via a macro to make it look pretty.

    (ns your.app
      (:require
        [goog.object :as gobj]
        ["something" :refer (Bar)]))
    
    (defn Foo
      {:jsdoc ["@constructor"]}
      []
      (this-as this
        (.call Bar this "data")
        ;; other constructor work
        this))
    
    (gobj/extend
      (.-prototype Foo)
      (.-prototype Bar)
      ;; defining x.foo(arg) method
      #js {:foo (fn [arg]
                  (this-as this
                    ;; this is Foo instance
                    ))})