ClojureScript

Externs

このガイドでは、ClojureScript 1.10.238 以降が必要であり、クイックスタートに精通していることを前提としています。.

このページでは、Google Closure Compilerの規約に準拠していないサードパーティのJavaScriptライブラリのexternsを記述する方法について説明します https://developers.google.com/closure/compiler/docs/limitations

動機

多くの便利なライブラリは、Google Closure Compilerの高度なコンパイルを経由できません。したがって、それらはビルドの一部になることができず、「外部」と見なされます。それでも、Closureはこれらのライブラリについて何かを知っている必要があります。そうしないと、プロパティが意図せずに名前変更される可能性があります。残念ながら、この誤った名前変更は、最も都合の悪い時期、つまり本番環境になるまで明らかにならないことがよくあります。

すでに成熟したexternsを持つライブラリの場合、この種の間違いは簡単に回避できます。ただし、この要件は、新しい、またはあまり一般的ではないが同様に便利なライブラリの採用に非常に大きな摩擦を加えます。externs推論の登場により、ClojureScriptコンパイラは、欠落しているexternsを自動的に生成できるようになっただけでなく、包括的なexternsの作成プロセスを大幅に支援できるようになりました。

Externs推論

外部ライブラリsome.fooLibを指定したとします。このライブラリに対して相互運用性を書きたいが、正しいexternsが自動的に生成されるか、コンパイラが追加で提供する必要のあるexternsを通知してくれることを確信したいとします。

externs推論を有効にするには、コンパイラ構成で:infer-externs trueを指定します。

次の内容でbuild.ednファイルを作成します

{:main my-project.core
 :output-to "out/main.js"
 :output-dir "out"
 :optimizations :none
 :infer-externs true})

ただし、これだけでは、コンパイラがexternsに関する警告を生成するのに十分ではありません。この機能が存在する前に書かれた多数のライブラリがあるため、この機能をグローバルな方法で有効にすることはできません。代わりに、Clojureの*warn-on-reflection*とやや類似した新しいファイルローカルコンパイラフラグ*warn-on-infer*があります。一度設定すると、コンパイラは、プロパティアクセスであろうとメソッド呼び出しであろうと、ドット形式に関与する型を判断できない場合、ファイルの残りの部分に対して常に警告します。

(ns my-project.core
  (:require [some.fooLib]))

(set! *warn-on-infer* true)

(defn wrap-baz [x]
  (.baz x))

上記のコードは警告メッセージをトリガーします

Cannot infer target type in expression (.baz x) ...

この相互運用呼び出しのために、xに外部型を型ヒントする必要があります

(ns my-project.core
  (:require [some.fooLib]))

(set! *warn-on-infer* true)

(defn wrap-baz [^js/Foo.Bar x]
  (.baz x))

コンパイラは、必要なexternsを自動的に生成するのに十分な情報を得ました。ビルドを実行すると、出力ディレクトリinferred_externs.jsに新しいファイルが表示されます。その内容を調べると、おそらく次のようになっているでしょう

var Foo = {};
Foo.Bar = function() {};
Foo.Bar.prototype.baz = function() {};

完全なexternsなしで外部JavaScriptライブラリをすばやく統合することが、はるかに簡単になり、エラーが発生しにくくなりました。

場合によっては、externsを記述したい場合や、成熟したexternsを持つ一般的なJavaScriptライブラリの消費者であり、もう少し検証が必要な場合があります。次のセクションでは、externs推論によって提供される追加の便利な機能について説明します。

戻り値の型

ローカル型ヒントは、externsを記述するプロセスを自動化するのに大いに役立ちます。ただし、相互運用性の高いコードの場合、特に一般的に使用される関数の戻り値の場合、多くの型ヒントが必要になります。この場合、externsファイルを提供する方がおそらく良いでしょう。ここでも、ClojureScriptコンパイラはプロセスを容易にすることができます

(ns my-project.core
  (:require [some.fooLib]))

(set! *warn-on-infer* true)

(defn my-fn [^js/Foo.Bar x]
  (let [z (.baz x)]
    (.-wozz z)))

externsファイルが次のようになっているとします

var Foo = {};
/**
 * @constructor
 */
Foo.Bar = function() {};
Foo.Bar.prototype.baz = function() {};
/**
 * @constructor
 */
Foo.Boo = function() {};
Foo.Boo.prototype.woz = function() {};

ただし、これはClojureScriptプログラムでzの型を知るには十分ではありません。ClojureScriptコンパイラは次の警告を発行します

WARNING: Adding extern to Object for property wozz due to ambiguous expression (. z -wozz) ...

externsファイルに戻り値の型情報を追加する必要があります

var Foo = {};
/**
 * @constructor
 */
Foo.Bar = function() {};
/**
 * @return {Foo.Boo} <-- CHANGED
 */
Foo.Bar.prototype.baz = function() {};
/**
 * @constructor
 */
Foo.Boo = function() {};
Foo.Boo.prototype.woz = function() {};

ソースファイルに触れてビルドを再実行すると、異なる警告が表示されます

WARNING: Cannot resolve property wozz for inferred type js/Foo.Boo in expression (. z -wozz)

ご覧のとおり、ClojureScriptは戻り値の型情報を使用して問題を明確にしました。

オリジナル作者:David Nolen