claspを使ってGoogle Apps Scriptをローカルで開発・編集する その2 - TypeScriptを使う

[claspを使ってGoogle Apps Scriptをローカルで開発・編集する その1 - claspを使ってみる](https://qiita.com/croquette0212/items/f78cc42d328131c3db43)の続き

# アップロードするディレクトリを分ける
## アップロード用ディレクトリの作成
既存のファイル一式をdistディレクトリに移動させる。

```
mkdir dist
mv コード.js dist/
mv appscript.json dist/
```
## .clasp.jsonにrootDirを追加する
```.clasp.json
{
  "scriptId":<スクリプトのID>,
  "rootDir": "dist"
}
```

`.clasp.json`ファイルがない場合は、手動で作成する。`rootDir`で指定したディレクトリ以下のファイルが`clasp push`でアップロードされるようになる。

## pushで動作確認する

試しにjsファイルの中身を少し変更して`push`してみる。

```
clasp push
clasp open
```

`dist`ディレクトリの中身がアップロードされていることを確認する。

# TypeScriptを使う
## TypeScriptのインストール(必要な場合)
```
npm install typescript -g
```

## tsディレクトリの作成
`ts`ディレクトリを作成し、現在のjsファイルを移動する。その際、拡張子を`.ts`に変更する。

```
mkdir ts
mv dist/コード.js dist/main.ts
```

## TypeScriptのオプションの設定
`tsc`コマンドを叩いたら`ts`ディレクトリの中にある`ts`ファイルから`dist`ディレクトリに`js`ファイルを書き出すようにする。

まずは設定ファイル(`tsconfig.json`)を作成する。

```
tsc --init
```

`tsconfig.json`を開き、`outDir`と`rootDir`を指定する。

```tsconfig.json
"outDir": "./dist",
"rootDir": "./ts",
```

## TypeScriptコンパイルする
```
tsc
```

`tsc`コマンドで`ts`ファイルを`js`ファイルにコンパイルする。このままだと型定義がないなどの警告が出るが、一応jsファイルの生成はできる。`dist`ディレクトリに`js`ファイルが生成されていることを確認する。

## GASの型定義ファイルを使う
GAS関連APIの定義が見つからずエラーが出力されてしまうので、`npm`でGAS用の型定義ファイルをダウンロードする。

```
npm init
```

`npm`を導入する。

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

これで、`ts`上でGAS関連クラスをimportできるようになる。

```
import Spreadsheet = GoogleAppsScript.Spreadsheet.Spreadsheet;
```

# LintとFormatterを使う
快適なTypeScriptライフのために、LintとFormatterを導入する。

## tslintの導入
```
npm install tslint --save-dev
```

Lintの設定は`recommended`にしてある。好みに応じて変更する。

```tslint.json
{
    "defaultSeverity": "error",
    "extends": [
        "tslint:recommended"
    ],
    "jsRules": {},
    "rules": {},
    "rulesDirectory": []
}
```

## typescript-formatterの導入
```
npm install npm install --save-dev typescript-formatter
```

### 試す
```
tsfmt -r ts/main.ts
```

`typescript-formatter`は`tslint.json`の値を尊重してくれるので嬉しい。

# タスクランナーの導入
## gulpを使う場合
### gulpを導入する
フォーマット、Lint、コンパイル…と処理が多くなるためgulpを導入する。せっかくなので`watch`をして`ts`ファイルを更新したら自動的にこれらの処理が走るようにする。

```
npm install gulp -g
```

```
npm install gulp
npm install gulp-notify --save-dev
npm install gulp-plumber --save-dev
npm install gulp-typescript --save-dev
npm install gulp-tslint --save-dev
npm install typescript --save-dev
npm install gulp-plugin-prettier prettier --save-dev 
```

```gulpfile.js
var gulp = require('gulp');
var notify = require("gulp-notify");
var plumber = require("gulp-plumber");
var typescript = require('gulp-typescript');
var tslint = require("gulp-tslint");
var prettier = require('gulp-plugin-prettier');

var paths = {
  'ts': './ts/',
  'dist': './dist/'
}

gulp.task('ts', () => {
  gulp.src([paths.ts + '**/*.ts', '!./node_modules/**'])
    .pipe(typescript())
    .pipe(gulp.dest(paths.dist));
 });

gulp.task("tslint", () =>
  gulp.src([paths.ts + '**/*.ts', '!./node_modules/**'])
    .pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") }))
    .pipe(tslint({
       formatter: "verbose"
    }))
    .pipe(tslint.report())
);

gulp.task('format', () =>
  gulp.src([paths.ts + '**/*.ts', '!./node_modules/**'])
    .pipe(prettier.format())
    .pipe(gulp.dest(file => file.base)),
);

gulp.task('watch', function () {
  gulp.watch([paths.ts + '**/*.ts'], ['format', 'tslint', 'ts']);
});

gulp.task('default', ['ts', 'watch']);
```

### gulpを実行
```
gulp
```

`watch`がはじまるので、適当に`ts`ファイルを編集・保存してみてフォーマット、Lint、コンパイルの処理が走るか確認する。

## npm scriptsを使う場合
最近は、Lint + Buildは`atom` + `atom-typescript`で行うのがおすすめ。

保存時の自動フォーマットは`atom-typescript`だけでは実現できないので、そこを実現したい場合は`npm scripts`で実現する。

```
npm install watch --save-dev
```

```package.json
  "scripts": {
    "watch": "watch 'tsfmt -r ts/*' ts"
  }
```

```
npm run watch
```