Mobile Factory Tech Blog

技術好きな方へ!モバイルファクトリーのエンジニアたちが楽しい技術話をお届けします!

社内勉強会を通じて DefinitelyTyped に新しいパッケージを追加した話

こんにちは、ブロックチェーンチームでソフトウェアエンジニアをしている id:odan3240 です。

モバファクには毎日1時間社内勉強会の制度があります。

tech.mobilefactory.jp

様々な目的の社内勉強会が開催されていますが、その中に一つOSSへの貢献が目的の勉強会があります。この勉強会の紹介は別の機会として、この記事では、この勉強会を通じてDefinitelyTyped に新しいパッケージの型定義を追加したので、その紹介をします。

DefinitelyTyped とは

DefinitelyTyped とは TypeScript の型定義を集めたリポジトリです。
TypeScript を書いているときに、 npm パッケージと一緒に @types/xxx というパッケージをインストールしたことがある方もいるかも知れません。この @types から始まるパッケージを集約しているリポジトリが DefinitelyTyped です。 DefinitelyTyped には型定義のない JavaScript 製のパッケージに対する型定義 1 が大量にあります。

今回は、keccak - npm に対する型定義を追加しました。

手順

コントリビュートの手順については README の How can I contribute? に丁寧に紹介されています。今回は新しいパッケージの追加だったため、Create a new package にある手順に沿って作業をしました。

ボイラープレートの作成

README にある通り、dts-gen を用いてボイラープレートを生成しました。今回の対象のモジュールは keccak なので、以下のコマンドを実行しました。

$ npx dts-gen --dt --name keccak --template module

このコマンドにより、index.d.ts, keccak-test.ts, tsconfig.json, tslint.json の4つのファイルが生成されます。
index.d.ts に型定義を、keccak-test.ts に型定義に対するテストを書くのが今回のゴールです。

テスト

.d.ts ファイルの lint やテストには dtslint が使用されます。

テストでは以下のように、コメントで期待される型を書く形式になっています。

const keccak = create('keccak224'); // $ExpectType Keccak

実際のプルリク

実際に出したプルリクはこれです。

feat: add types of keccak by odanado · Pull Request #44016 · DefinitelyTyped/DefinitelyTyped

typescript-bot という bot が住んでいます。この bot はレビューが遅れていると、「もう少し待ってね」というコメントを付けるようです。個人的に放置されている感じが少なくて良いと思いました。

感想

keccak はブロックチェーンの Ethereum で使用されているハッシュ関数です。Ethereum に関するコードを書く時によく使用していましたが、型定義が存在しないのがいつも気になっていました。そんな中、 OSS への貢献を目的とした社内勉強会が開催されると聞いて良い機会と感じて keccak の型定義を追加するプルリクを作成しました。

DefinitelyTyped には世界中のエンジニアが協力して型定義のない npm パッケージに型定義を追加しています。仕事でも趣味でも TypeScript を書いている人間としては DefinitelyTyped には普段からお世話になっています。今回は、これに自分も協力できたという実感があり、感慨深いです。


  1. 元の npm パッケージに型定義が含まれている場合もある

Vue.observable でエラーの状態管理を行う

こんにちは、ブロックチェーンチームでソフトウェアエンジニアをしている id:odan3240 です。

ページをまたぐエラーを制御したい場合、グローバルな状態管理を行えるVuex が選択肢に上がるかと思います。しかし、Vue.js 2系に対応する 3系の Vuex は公式の TypeScript サポートがなく TypeScript と相性が悪いことが知られています。エラー状態管理のような規模の小さいものなら Vue.observable を利用すれば良いのでは?と考え実装してみたところ、いい感じになったので紹介します。

前提知識

Vue.observable とは

Vue.observable は Vue.js 2.6 から追加された API です。この API はオブジェクトをリアクティブにすることができます。コンポーネントの data 関数の返り値がリアクティブになるのと同じ仕組みです。

jp.vuejs.org

Vue.js におけるエラーハンドリング

Vue.js では処理されていない例外が検知された場合、Vue.config.errorHandler に登録されている関数を呼び出します。つまり、ここに関数を登録すれば独自のエラー処理を実装することができます。

jp.vuejs.org

Vue.js のプラグイン

Vue.js のプラグインを使用することで、Vue のインスタンス、つまり this にプロパティを生やすことが可能です。プラグインはアプリケーションの初期化時に呼び出されるようにする必要があります。

jp.vuejs.org

実装例

今回紹介する実装例は以下のリポジトリに置いています。

github.com

src/plugins/error.ts を実装する

src/plugins/error.ts を簡略化しています。

import Vue, { PluginObject } from "vue";

export type Options = {};

// 状態の型を定義
export type State = {
  hasError: boolean;
  message: string;
};

// this.$error でアクセスできるように型定義を拡張
declare module "vue/types/vue" {
  interface Vue {
    $error: State;
  }
}

// エラーの状態を Vue.observable を使って定義
const state = Vue.observable<State>({ hasError: false, message: "" });

// エラーが発生するとこの関数が呼ばれる
Vue.config.errorHandler = err => {
  // エラーが存在することと、その内容を格納
  state.hasError = true;
  state.message = err.message;

  // 3秒後にエラーの状態をクリア
  setTimeout(() => {
    state.hasError = false;
    state.message = "";
  }, 3000);
};

export const errorPlugin: PluginObject<Options> = {
  install(Vue) {
    // this.$error に state を注入
    Vue.prototype.$error = state;
  }
};

コンポーネント側

コンポーネント側の使用例を示します。src/App.vue を簡略化しています。

<template>
  <div id="app">
    <div>
      <button @click="click">click me!</button>
    </div>
    <div v-if="hasError">{{ errorMessage }}</div>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
export default Vue.extend({
  name: "App",
  methods: {
    click() {
      throw new Error("Error! yabai!");
    }
  },
  computed: {
    // this.$error.hasError と this.$error.message はエラーが発生すると自動的に値が変わる(リアクティブ)
    hasError() {
      return this.$error.hasError;
    },
    errorMessage() {
      return this.$error.message;
    }
  }
});
</script>

このような実装をしておくと、アプリケーションで発生した例外を自動的にキャッチして、リアクティブな変数 state の状態が変更され、自動的に errorMessage が表示されます。

まとめ

Vue.observable を使ってエラー管理用のリアクティブな変数を用意して、Vue.config.errorHandler で更新し、その変数に対して this 経由でアクセスする方法を紹介しました。

Vue.observable を使ったサンプルは日本語ではあまりヒットしなかったので、今回記事にしてみました。