Typescript + Node.jsの素振りとして、「BacklogとJiraのdiffをとってJSONに吐き出す」スクリプトを作りました。
backlog-jira-diff

作ろうと思った背景としては以下です。完全に自分用です。

  • BacklogとJiraの両方を使用していて二重管理になっている
  • Jiraのチケットを完了にしたのに紐づくBacklogの課題を完了にしわすれてしまう


Backlogで未完了の課題のIssueKeyをJiraチケットのタイトル or 説明欄に含めるというルールで運用されているという前提です。

Backlog APIとJira APIについては、クライアントライブラリがあったのでAPI呼び出し部分を自分で実装することなく楽ができました。


Gatsby.jsのTypescript化をしたので、Node.js環境でのTypeScriptを書いた経験は一応あるのですが、ノンフレームワークな素のNode.js + TypeScriptは初めてだったので詰まったところを記録しておきます。
というか振り返ってみたらそもそもNode.jsすらロクに書いたことがなかった。

dotenvの環境変数読み込み

.envファイルから環境変数を読み込むためにdotenvをimportして使用することは一般的だと思います。ただ、コードの位置によってprocess.envから取得できたりできなかったりしました。
原因は、dotenv.config()の実行位置でした。config()実行時に.envから環境変数を取得してprocess.envに反映してくれるようです。
import直後にconfig()を実行するようにしたら、process.envからundefinedではなくちゃんと設定した期待通りの値が帰ってくるようになりました。

 import dotenv from "dotenv";
  dotenv.config();  

Promise.all()の使い所

Promiseについては、JavaScript Promiseの本で学習しました。
概念はなんとなく覚えていたのですが、具体的な使用場面が想像できないままで使った経験もありませんでした。
ただ、今回はBacklogの課題一覧取得のAPIの制約(取得上限が100件)により、プロジェクトごとに別々のAPI呼び出しが必要だと考え、Promise.allを使ってみました。

 const undoneTickets: BacklogGetIssuesResponse[][] = await Promise.all(
      this.targetProjectIds.map(
        async (projectId) =>
          (await this.client.getIssues({
            projectId: [projectId],
            keyword: "",
            statusId: this.undoneStatusIds,
            count: 100,
          })) as BacklogGetIssuesResponse[]
      )
    );
  

mapでPromiseの配列を受け取りそれらがすべてresolveされるまで待つ、というのがちゃんと理解できました。

ライブラリからimportするときによくみる「@」

import時のpathの指定を相対パスではなく、絶対パスで書くための記法。必ずしも@から始まる必要はないが@がスタンダードっぽい。
tsconfig.jsonのpathsの指定で設定できる。

 // tsconfig.json
    "baseUrl": "./",
    "paths": {
      "@types": ["./src/types"]
    }

    // importする側
    import { SearchJiraResponse, DoneJiraTicket } from "@types";