Electron を TypeScript で書く

Electronを動かしてHello world!表示するまで(macOS) で試作したElectronアプリを、JavaScript から TypeScript へ書き換えてみました。

JSからTSへ移行する流れ

  1. Electronアプリで作成したjsとhtmlファイルをsrcへ移動
  2. jsファイルは拡張子をtsへ変更(内容も適宜変更)
  3. tsconfig.jsonを用意する
  4. package.jsonを修正する

sh
$ tree -I node_modules
.
├── default.txt
├── dist
│   ├── index.html
│   ├── main.js
│   └── preload.js
├── package-lock.json
├── package.json
├── src
│   ├── index.html
│   ├── main.ts
│   └── preload.ts
└── tsconfig.json

JSからTSへ移行する手順

それでは既存のElectronプロジェクトをTypeScriptに移行していきます。

TypeScriptのインストール

プロジェクトディレクトリで以下のコマンドを実行して、TypeScriptをインストールします。

sh
npm install --save-dev typescript

tsconfig.jsonの作成

プロジェクトのルートディレクトリにtsconfig.jsonファイルを作成し、以下の内容を追加します。

json
{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "resolveJsonModule": true,
    "noImplicitAny": true,
    "moduleResolution": "node",
    "skipLibCheck": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}

プロジェクト構造の変更

JavaScriptファイルをTypeScriptファイルにリネームします。例えば、main.jsmain.tsに変更します。src ディレクトリも作成し、そこへソースコードを移動させておきます。

ビルドスクリプトの設定

package.jsonにビルドとコピーのスクリプトを追加します。ここではcopyfilesパッケージを使用して、HTMLファイルをコピーします。

sh
npm install --save-dev copyfiles

次に、package.jsonのスクリプトセクションを以下のように更新します。

json
  "scripts": {
    "build": "tsc && npm run copy-html",
    "copy-html": "copyfiles -u 1 src/*.html dist",
    "start": "npm run build && electron ./dist/main.js"
  },

必要な型定義パッケージのインストール

Electronの型定義パッケージをインストールします。

sh
npm install --save-dev @types/node @types/electron

ソースコードの修正

TypeScriptの型定義に従って、ソースコードを修正します。例えば、requireを使用している部分をimportに置き換えるなど。

ts
// src/main.ts
import {app, BrowserWindow, ipcMain, dialog} from 'electron';
import fs from 'fs';
import path from 'path';

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    }
  });

  win.loadFile('index.html');
  win.webContents.openDevTools();
}

app.whenReady().then(createWindow);

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

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

ipcMain.on('save-file', async (event: { reply: (arg0: string, arg1: string) => void; }, data: any) => {
  const result = await dialog.showSaveDialog({
    title: 'Save File',
    defaultPath: path.join(__dirname, 'default.txt'),
    buttonLabel: 'Save',
    filters: [
      { name: 'Text Files', extensions: ['txt'] },
      { name: 'All Files', extensions: ['*'] }
    ]
  });

  if (!result.canceled) {
    fs.writeFile(result.filePath.toString(), data, (err: any) => {
      if (err) {
        console.error('File Save Error:', err);
        event.reply('save-file-response', 'error');
      } else {
        console.log('File Saved Successfully');
        event.reply('save-file-response', 'success');
      }
    });
  } else {
    event.reply('save-file-response', 'canceled');
  }
});

また、型指定ができるようになるので、WebStormなどのIDEの機能を使って内容を適宜修正します。

ts
// src/preload.ts
import {contextBridge, ipcRenderer} from 'electron';

contextBridge.exposeInMainWorld('electron', {
  saveFile: (content: any) => ipcRenderer.send('save-file', content),
  onSaveFileResponse: (callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void) => ipcRenderer.on('save-file-response', callback),
});

プロジェクトのビルドと実行

以下のコマンドでプロジェクトをビルドし、Electronアプリを実行します。

sh
npm run start

これで、既存のElectronプロジェクトをTypeScriptに移行する基本的な手順は完了です。

関連記事

最後までご覧いただきありがとうございます!

▼ 記事に関するご質問やお仕事のご相談は以下よりお願いいたします。
お問い合わせフォーム