Hori Blog

フリーランスでバックエンドエンジニアとして活動している Ryota Hori のブログです。
最近はテック系記事より雑記ブログ気味。

TypeScript で Google Apps Script を書く環境を整備する

無料で自動化環境を整備できることで有名な Google Apps Script ですが、以前はブラウザで JavaScript を用いて開発する必要があったため辛い部分もありました(人による)。

現在は公式からローカル開発をするための公式 CLI ツールが提供されているので、静的型付けの恩恵を受けるべく TypeScript を用いて開発できるようにしてみました。

公式の CLI ツール

インストール自体は Node.js が入っている環境であれば npm install で入れられます。

npm install -g node-google-apps-script

初期設定として認証キーの発行などが必要です。GitHub の README.md に全て載っていますが、日本語情報ですと以下のブログが詳しかったのでご参照ください。

Google Apps Script の開発をモダンに行う方法 - Speee DEVELOPER BLOG

ディレクトリ構成

directory-structure
dev/
node_modules/
src/
.gitignore
gapps.config.json
package.json
README.md
tsconfig.json

こんな感じです。 CLI がデフォルトで src/ ディレクトリのものをアップロードするため、 dev/ を開発用のディレクトリとし、コンパイルした生成ファイルを src/ に置くようにします。( gapps.config.json で設定できそうなので気持ち悪ければ変更すればよさそうですね。)

ローカル開発なので Git でバージョン管理できるの最高ですね!テストは今回は省略しています。

node_modules

TypeScript で開発するために Google Apps Script 用の型定義ファイルを取得します。

npm install --save-dev @types/google-apps-script

TypeScript 2.0 から tsd や typings は不要になったようですね。

tsconfig.json

tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "./src",
    "rootDir": "./dev",

    "alwaysStrict": true,
    "inlineSourceMap": true,
    "noEmitOnError": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "pretty": true,
    "strictNullChecks": true
  }
}

オプションは適当です。開発用ディレクトリを dev/ 、出力ディレクトリを src/ としたのでそれぞれ設定しています。

これで tsc とコンパイルを実行すれば src/ ディレクトリに js ファイルが出力されるので、 Google Apps Script にアップロードすれば OK です。

npm scripts

そんなに複雑なコマンドは使いませんが、 npm scripts 化しておきます。

package.json に以下を定義。

package.json
  "scripts": {
    "publish": "npm run build && npm run upload",
    "build": "npm run tsc",
    "tsc": "tsc",
    "upload": "gapps upload"
  },

これで簡単にコンパイルとアップロードができます。

npm run publish

サンプル

サンプルとして POST リクエストでカレンダーの予定を作成するスクリプトを作ってみました。 Google Apps Script 独自の Service などは型定義ファイルに global 定義されているのでそのまま使えます。

gas-sample.ts
const calendarId = 'sample@group.calendar.google.com'; // replace to your calendar id

class PostEvent {
  queryString: string;
  parameter: { [index: string]: string; };
  parameters: { [index: string]: [string]; };
  contentLenth: number;
  postData: {
    length: number;
    type: string;
    contents: string;
    name: string;
  };
}

function _test() {
  let e = new PostEvent;
  e.postData = {
    length: 0,
    type: "",
    contents: '{"title":"sample title", "startTime": "2017-03-19T09:00:00.000Z", "endTime": "2017-03-19T12:00:00.000Z"}',
    name: ""
  };
  doPost(e);
}

class CalendarEvent{
  title: string;
  startTime: Date;
  endTime: Date;
}

function doPost(e: PostEvent):GoogleAppsScript.Content.TextOutput {
  let calendarEvent = new CalendarEvent;
  let contents = JSON.parse(e.postData.contents)
  calendarEvent.title = contents.title
  calendarEvent.startTime = new Date(contents.startTime)
  calendarEvent.endTime = new Date(contents.endTime)
  let result = JSON.stringify(calendarEvent);
  return ContentService.createTextOutput(result);
}

function createEvent(e: CalendarEvent) {
  CalendarApp.getCalendarById(calendarId).createEvent(
    e.title,
    e.startTime,
    e.endTime,
  )
}

以上

以前は Logger.log などで頑張ってデバッグしていたのですが、コンパイル時点でタイプミスなどを検知できてとても管理しやすいです。

Google Apps Script は業務効率化と非常に相性がいい反面、管理が属人化しがちなのが悩みだったのですが、 ローカル開発によって Git 管理やテストが可能になるだけでなく、 TypeScript で静的型付けの恩恵まで受けられるようになったので更に便利になりました。

SpreadSheet や手動スクレイピング芸などで疲弊している方々はたくさんいると思いますので、ちょろっとスクリプトを書いて自動化できるところはガンガンやっていきたい所存です。

今回のサンプルは GitHub に置いてあるので、雛形としてお使いください。

hori-ryota/gas-typescript