はじめに
いつか触ろうと思って触ってなかった clasp
https://qiita.com/HeRo/items/4e65dcc82783b2766c03
を参考にしながら触ってみた。
しかも @google/clasp v1.5.0 から TypeScript をサポートしていて、
トランスパイルも自動的にやってくれるとのこと。
但し、TS ファイルから自動的に GS ファイルに変換されたものを
clasp clone
や clasp pull
すると、変換後の結果が JS ファイルとしてダウンロードされるらしい。
ので、最初からトランスパイル後のファイルを clasp push
したら良いのかな?と試してみた記録です。
前提
複数ファイルに分割していない場合は直接 push しても、
トランスパイル後のファイルを push しても変わりはなかったので、
複数ファイルを用意して試す。
push 対象の TS ファイル
import { outputLog } from './hoge';
function myFunction() {
outputLog();
}
export function outputLog(): void {
Logger.log('Hello World!');
}
TS ファイルを直接 clasp push した場合
初めに普通にそのまま push するパターン
.clasp.json
の rootDir で push 対象ディレクトリを指定。
$ clasp push
└─ src/appsscript.json
└─ src/code.ts
└─ src/hoge.ts
Pushed 3 files.
変換された GS ファイル
// Compiled using ts2gas 3.4.4 (TypeScript 3.6.2)
var exports = exports || {};
var module = module || { exports: exports };
//import { outputLog } from './hoge';
function myFunction() {
outputLog();
}
//# sourceMappingURL=module.js.map
↑import 文が勝手にコメントアウトされてた。
ts2gas 3.4.4
っていうのを使ってるみたい?
// Compiled using ts2gas 3.4.4 (TypeScript 3.6.2)
var exports = exports || {};
var module = module || { exports: exports };
function outputLog() {
Logger.log('Hello World!');
}
exports.outputLog = outputLog;
//# sourceMappingURL=module.js.map
myFunction 実行結果

まぁ普通にいける
トランスパイルした JS ファイルを clasp push した場合
tsconfig.json で dist
以下にトランスパイルファイルを出力するようにした。
合わせて .clasp.json
の rootDir は dist
に変更した。
module="es2015", target="es5"
$ clasp push
| Pushing files...Push failed. Errors:
{ Error: Syntax error: Missing ; before statement. line: 1 file: code
at Gaxios.request (/Volumes/sdcard/Bin/.nodenv/versions/10.15.1/lib/node_modules/@google/clasp/node_modules/gaxios/build/src/gaxios.js:70:23)
at process._tickCallback (internal/process/next_tick.js:68:7)
response:
{ config:
{ url:
'https://script.googleapis.com/v1/projects/xxxxxxxxxx/content',
method: 'PUT',
paramsSerializer: [Function],
data: [Object],
headers: [Object],
params: [Object: null prototype] {},
validateStatus: [Function],
retry: true,
body:
'{"scriptId":"xxxxxxxxxx","files":[{"name":"appsscript","type":"JSON","source":"{\\n \\"timeZone\\": \\"Asia/Tokyo\\",\\n \\"dependencies\\": {\\n },\\n \\"exceptionLogging\\": \\"STACKDRIVER\\"\\n}"},{"name":"code","type":"SERVER_JS","source":"import { outputLog } from \'./hoge\';\\nfunction myFunction() {\\n outputLog();\\n}\\n//# sourceMappingURL=code.js.map"},{"name":"hoge","type":"SERVER_JS","source":"export function outputLog() {\\n Logger.log(\'Hello World!\');\\n}\\n//PropertiesService.getScriptProperties().getProperty(\'HOGE\')\\n//# sourceMappingURL=hoge.js.map"}]}',
responseType: 'json',
retryConfig: [Object] },
data: { error: [Object] },
headers:
{ 'alt-svc': 'quic=":443"; ma=2592000; v="46,43,39"',
'cache-control': 'private',
connection: 'close',
'content-encoding': 'gzip',
'content-type': 'application/json; charset=UTF-8',
date: 'Mon, 09 Sep 2019 04:43:21 GMT',
server: 'ESF',
'transfer-encoding': 'chunked',
vary: 'Origin, X-Origin, Referer',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '0' },
status: 400,
statusText: 'Bad Request' },
config:
{ url:
'https://script.googleapis.com/v1/projects/xxxxxxxxxx/content',
method: 'PUT',
paramsSerializer: [Function],
data:
{ scriptId: 'xxxxxxxxxx',
files: [Array] },
headers:
{ 'Accept-Encoding': 'gzip',
'User-Agent': 'google-api-nodejs-client/2.0.4 (gzip)',
Authorization:
'Bearer ya29.Glx-B1azGu5jyQ_tkABZ9n6mmnDuPnn5uZLM44sOwDMXfAt3mC7Bem5Dmi9joKJ3lmvg7vNy87f37h0muiiccVOdO1Uv-n4YQLqLasp5r03_EzZZAlQ1_AHCt_70bg',
'Content-Type': 'application/json',
Accept: 'application/json' },
params: [Object: null prototype] {},
validateStatus: [Function],
retry: true,
body:
'{"scriptId":"xxxxxxxxxx","files":[{"name":"appsscript","type":"JSON","source":"{\\n \\"timeZone\\": \\"Asia/Tokyo\\",\\n \\"dependencies\\": {\\n },\\n \\"exceptionLogging\\": \\"STACKDRIVER\\"\\n}"},{"name":"code","type":"SERVER_JS","source":"import { outputLog } from \'./hoge\';\\nfunction myFunction() {\\n outputLog();\\n}\\n//# sourceMappingURL=code.js.map"},{"name":"hoge","type":"SERVER_JS","source":"export function outputLog() {\\n Logger.log(\'Hello World!\');\\n}\\n//PropertiesService.getScriptProperties().getProperty(\'HOGE\')\\n//# sourceMappingURL=hoge.js.map"}]}',
responseType: 'json',
retryConfig:
{ currentRetryAttempt: 0,
retry: 3,
retryDelay: 100,
httpMethodsToRetry: [Array],
noResponseRetries: 2,
statusCodesToRetry: [Array] } },
code: 400,
errors:
[ { message:
'Syntax error: Missing ; before statement. line: 1 file: code',
domain: 'global',
reason: 'badRequest' } ] }
└─ dist/appsscript.json
└─ dist/code.js
└─ dist/hoge.js
↑なんかエラー出た。
push しようとしたトランスパイル結果
import { outputLog } from './hoge';
function myFunction() {
outputLog();
}
//# sourceMappingURL=code.js.map
export function outputLog() {
Logger.log('Hello World!');
}
//# sourceMappingURL=hoge.js.map
↑普通に import/export なやつ。
module="commonjs", target="es5"
$ clasp push
└─ dist/appsscript.json
└─ dist/code.js
└─ dist/hoge.js
Pushed 3 files.
↑clasp push できた
トランスパイル結果を push して変換された GS ファイル
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var hoge_1 = require("./hoge");
function myFunction() {
hoge_1.outputLog();
}
//# sourceMappingURL=code.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function outputLog() {
Logger.log('Hello World!');
}
exports.outputLog = outputLog;
//# sourceMappingURL=hoge.js.map
↑requre 系なやつ。
ちなみに dist 以下に出力された dist/code.js
と dist/hoge.js
と中身は同じ。
ファイル名だけ .gs
に変換されている模様
myFunction 実行結果

実行ができなかった!
まとめ
import を使わない場合はトランスパイル後の JS ファイルを push しても問題はない。
でも clasp に任せて TS ファイルを直接 push したほうが良さそう。
push した TS ファイルは GS ファイルに変換されているので、
次回 clasp clone
, clasp pull
等をすると変換後の GS ファイルがダウンロードされてしまう。
TS ファイルは別途、Git 等で管理したほうが良さそう。