TypeScriptでElectronアプリを書いてみる


## 目標

素のJavaScriptを一切使わずに、TypeScriptのみでElectronアプリを書いてみます。
とりあえずはハローワールドぐらいのものを目標にします。

## 前提

以下のものはすでにインストールされているとします。

- Node.js
- npm
- TypeScript
- Electron

上記のソフトウェアのインストール方法は検索すればたくさん出ます。

## 準備

### プロジェクトフォルダを作成する

好きな場所にフォルダを用意しておきます。

```shell:例
$ cd ~/
$ mkdir electron-practice
$ cd electron-practice
```

### プロジェクトの作成

```shell:
$ npm init -y
```

これで、アプリに必要なpackage.jsonファイルが作成されます。

### TSDのインストール

>注意：現在はtsdではなくtypingsを使うほうが良いようです。(2016/3/6追記）

TypeScriptでは、型定義ファイルがあったほうがよいのでElectron用の型定義ファイルをダウンロードしておきます。

[TSD](https://github.com/DefinitelyTyped/tsd)を使うのが簡単なので、TSDを使ってダウンロードします。

```shell:
$ npm install tsd -g
$ tsd install github-electron --save
```

- tsd.json
- typings/github-electron/github-electron.d.ts 
- typings/node/node.d.ts

の３つのファイルが作成されます。
このうち、今回使うのは、github-electron.d.tsです。


> 参考：[TypeScriptの型定義ファイルを共有しよう！](http://qiita.com/vvakame/items/1980d4b6cc222e03fdcb)


## コードを書いていきます

すべてのコードは、プロジェクトフォルダ直下に書いてみます。
余裕のある方は、フォルダごとに整理した方が良いでしょう。

### index.html

```html:index.html
<!DOCTYPE html>
<html>
<head>
  <title>Hello TypeScript</title>
</head>
<body>
  <h1>Hello TypeScript</h1>
</body>
</html>
```

### index.ts

```typescript:index.ts
/// <reference path="typings/github-electron/github-electron.d.ts" />

const electron = require('electron');
const BrowserWindow: typeof Electron.BrowserWindow = electron.BrowserWindow;
const app: Electron.App = electron.app;

class MyApplication {
    mainWindow: Electron.BrowserWindow = null;

    constructor(public app: Electron.App){
        this.app.on('window-all-closed', this.onWindowAllClosed);
        this.app.on('ready', this.onReady);
    }

    onWindowAllClosed(){
        if(process.platform != 'darwin'){
            this.app.quit();
        }
    }

    onReady(){
        this.mainWindow = new BrowserWindow({
            width: 800,
            height: 400,
            minWidth: 500,
            minHeight: 200,
            acceptFirstMouse: true,
            titleBarStyle: 'hidden'
        });

        this.mainWindow.loadURL('file://' + __dirname + '/index.html');

        this.mainWindow.on('closed', () => {
            this.mainWindow = null;
        });
    }
}

const myapp = new MyApplication(app);
```

コメントでご指摘いただいたimportまわりを修正してみました。

>コメントどおりに、```import {BrowserWindow} from 'electron'```とすると
>```Cannot compile modules unless the '--module' flag is provided.```
>というエラーが出たので、```require('electron').BrowserWindow```にしています。
>メインのファイルでなければmoduleにしてもよさそうですが、
>メインをmoduleにしようとするとなんかハマるので今回はこんな感じで誤魔化しました。
>旧版とあまり変わり映えしないですね（汗

追記(2015/12/30）：classを使って全面的に書き換えてみました。

### index.ts（旧）

以下のindex.tsファイルは古いので使わないでください。
参考までに残してあります。

```typescript:index.ts
/// <reference path="typings/github-electron/github-electron.d.ts" />

var app: GitHubElectron.App = require('app');
var BrowserWindow: typeof GitHubElectron.BrowserWindow = require('browser-window');

var mainWindow: GitHubElectron.BrowserWindow = null;

app.on('window-all-closed', () => {
    if(process.platform != 'darwin'){
        app.quit();
    }
});

app.on('ready', () => {
    mainWindow = new BrowserWindow({
        width: 800,
        height: 400,
        titleBarStyle: 'hidden'
    });

    mainWindow.loadURL('file://' + __dirname + '/index.html');

    mainWindow.on('closed', () => {
        mainWindow = null;
    });
});
```

## コンパイル

index.tsを.jsファイルにコンパイルします。

```shell:
$ tsc index.ts
```

そうすると、index.jsファイルが作成されます。

## 実行

これで必要なファイルが揃いましたので、electronで実行してみましょう。

```shell:
$ electron .
```

ウィンドウが表示されたら成功です。

## 補足（旧版index.tsに関わる話）

一番苦労したのは、index.tsファイルの４行目
```var BrowserWindow: typeof GitHubElectron.BrowserWindow = require('browser-window');```
のところです。

import文をなんとか使えないかと四苦八苦したのですが無理でした。
Stackoverflowにずばり「[Importing Electron classes with Typescript](http://stackoverflow.com/questions/31302253/importing-electron-classes-with-typescript)」という記事があったのですが、この記事は不完全で、このままだと、

```
Cannot use 'new' with an expression whose type lacks a call or construct signature.
```

というコンパイルエラーがでます。

いろいろ試行錯誤してみた結果、```GitHubElectron.BrowserWindow```の前に```typeof```が抜けていたようです。
よく考えてみれば、```var BrowserWindow```の型は```GitHubElectron.BrowserWindow```ではなく、```GitHubElectron.BrowserWindow```を表す型なんですよね……気付けば納得なんですが、気付くまでかなり時間がかかりました。

## 参考

[30分で出来る、JavaScript (Electron) でデスクトップアプリを作って配布するまで](http://qiita.com/nyanchu/items/15d514d9b9f87e5c0a29)
[Electronでアプリケーションを作ってみよう](http://qiita.com/Quramy/items/a4be32769366cfe55778)