名前空間したい

1const 名前空間 = {キー: 値};

GASエディターで直接.gs(.js)ファイルを編集していると、 プロジェクト内のすべての関数はファイルをまたいでグローバルに定義されます。 そのため、ファイル名を分けても、同じ名前の関数は共存できません。

もし、同じ名前の関数を使用する必要がある場合、 オブジェクト型を使って名前空間(のようなもの)を定義できます。 これは言語機能としての名前空間ではなく、 グローバルな関数名の衝突を避けるための、GASエディター上での実装上の工夫です。

注釈

オブジェクトを使った名前空間の作成は、モジュール(importやrequire)が標準化される以前のJavaScriptで一般的な方法だったようです。 GASエディターにはモジュールシステムがないため、今でも同じ発想が有効です。

1// ns1.gs
2const ns1 = {
3    sameFnName: function (arg) {
4        Logger.log("これは ns1 の関数");
5    }
6};
1// ns2.gs
2const ns2 = {
3    sameFnName: function (arg) {
4        Logger.log("これは ns2 の関数");
5    }
6};
1// ns3.gs
2const ns3 = {};
3ns3["sameFnName"] = function (arg) {
4    Logger.log("これは ns3 の関数");
5};
1// main.gs
2function main() {
3    ns1.sameFnName();  // -> これは ns1 の関数
4    ns2.sameFnName();  // -> これは ns2 の関数
5    ns3.sameFnName();  // -> これは ns3 の関数
6}

GASエディターでは、ns1.gs・ns2.gs・ns3.gs・main.gsのようにファイルを分けて保存しても、 1つのプロジェクトとしてすべてまとめて実行されます。 ns1・ns2・ns3はそれぞれ別の変数名なので、 中のsameFnNameという同じ名前のプロパティが衝突することはありません。

注意

ns3["sameFnName"]のようにブラケット記法でキーを指定する場合、 キー名はクォートで囲んだ文字列にする必要があります。 ns3[sameFnName](クォートなし)と書くと、 sameFnNameという名前の変数を探しにいってしまい、 そのような変数が存在しなければReferenceErrorになります。

注意

GASはV8エンジン対応でモダンなJSを使えるようになりましたが、ES6のモジュールシステムはサポートされてないらしいです。 いろいろがんばればモジュールシステムを使うこともできるようですが、ここでは深追いしません。

tsc + rollupが使える場合は

ここまでの「オブジェクトによる疑似的な名前空間」は、 GASエディターに直接コードを書くスタイル特有の工夫です。 tsc + rollup + claspのワークフローが組める場合は、 そもそもファイルごとにモジュールスコープが分かれるため、 この工夫自体が不要になります。 同じ関数名を別ファイルで使いたい場合は、 export/importで明示的にやり取りすればよく、 グローバルな名前の衝突を意識する必要はありません。

ヒント

TypeScriptにはnamespaceという専用の構文もあります。 @types/google-apps-scriptの型定義(GoogleAppsScript.Driveなど)は 実際にこの構文で書かれていますが、 これは型定義パッケージ側の実装の都合によるものです。 自分のプロジェクトのコードでモジュールを分けたい場合は、 namespaceではなくexport/importを使うほうが今風です。

リファレンス