LoginSignup
8
2

More than 3 years have passed since last update.

Riot v4 で TypeScript がサポートされたので使ってみた

Last updated at Posted at 2019-12-01

環境構築

インブラウザ・コンパイル では TypeScript が使えないので webpack などのローダーを使う必要があります。
サクッと環境構築するために、公式で用意されているサンプルをベースにしました。
https://github.com/riot/examples/typescript

ダウンロード

https://github.com/riot/examples
[Clone or download] -> [Download ZIP]
Download ZIP

すべてのexampleがダウンロードされるので、その中にあるtypescriptを使います。

インストール

cd ./path/to/riot-examples/typescript
npm install

起動

npm start

ブラウザで↓を開くと乱数を生成するサンプルが表示されます。
http://localhost:3000/
スクリーンショット 2019-11-30 11.52.43.png

TypeScriptでのRiotコンポーネントの書き方

riot-example/typescript のコードを JavaScript の記述と比べながら確認してみます。

random.riot のテンプレート部分

random/random.riot
<random>
  <h3>{ props.title }</h3>

  <button onclick={ generate }>
    Generate
  </button>

  <h1>
    { state.number }
  </h1>

  <logs logs={ state.logs } onclear={ clearLogs }></logs>

  <script type="ts">
    // ...(省略)
  </script>
</random>

こちらは JavaScript で書く方式と同じですね。

random.riot の Script 部分

random/random.riot
<random>
  <!-- (省略) -->
  <script type="ts"> // (1)
    import Logs from '../logs/logs.riot'
    import {RandomComponent} from './types' // (2)

    function Random(): RandomComponent { // (3)
      return {
        state: {
          number: null,
          logs: []
        },
        generate(event: MouseEvent): void { // (4)
          this.update({
            number: Math.floor(Math.random() * 10000),
            logs: this.state.logs.concat({
              text: `Generate button clicked. Event type is ${event.type}`
            })
          })
        },
        clearLogs(): void {
          this.update({
            logs: []
          })
        }
      }
    }

    Random.components = {
      Logs
    }

    export default Random
  </script>
</random>
  1. TypeScript であることを type="ts" で指定します。

  2. 後述する型定義ファイルをインポートしています。

  3. 一見ガラッと変わっているように見えますが、JavaScriptでもファクトリ関数を使ってコンポーネント生成ができるので同じです。
    https://riot.js.org/ja/api/#ステートハンドリング

  4. 引数と戻り値の型が指定できます。

random.riot と対になっている types.ts

random/types.ts
import {RiotComponentExport} from 'riot'

export interface RandomComponentState { // (1)
  number: number | null;
  logs: { text: string }[];
}

export interface RandomComponentProps { // (1)
  title: string;
}

export interface RandomComponent extends RiotComponentExport<RandomComponentProps, RandomComponentState> { // (2)
  generate(event: MouseEvent): void;
  clearLogs(): void;
  state: RandomComponentState;
}

JavaScript で記述する際には存在しない型定義ファイルで、コンポーネントのインターフェースが定義されています。

  1. propsstate のフィールドとそれぞれの型が指定できます。
  2. メソッドの定義を指定できます。

TypeScript の恩恵はどこで受けられるの?

ここが一番のポイントだと思うので色々試してみました。

number 型で定義されている変数に文字列を入れる

function Random(): RandomComponent {
  return {
    state: {
      number: 'riot.js', // <-- ここを変更
      logs: []
    },
    // ...
  }
}

// -------------------------------
// random.riot.ts
// Error 2322 : Type 'string' is not assignable to type 'number | null'.

アサインできない型なのでエラーになりました。

types.ts にだけ関数を追加する

export interface RandomComponent extends RiotComponentExport<RandomComponentProps, RandomComponentState> {
  generate(event: MouseEvent): void;
  clearLogs(): void;
  hoge(): void; // <-- ここに追加
  state: RandomComponentState;
}

// -------------------------------
// random.riot.ts
// Error 2741 : Property 'hoge' is missing in type '{ state: { number: null; logs: never[]; }; generate(event: MouseEvent): void; clearLogs(): void; }' but required in type 'RandomComponent'.

インターフェースが定義されているのに実装が存在していないのでエラーになりました。
types.tsstate にだけフィールドを追加した場合も同様の結果でした。

random.riot にだけ関数を追加する

function Random(): RandomComponent {
  return {
    // ...
    clearLogs(): void {
      this.update({
        logs: []
      })
    },
    fuga(): void { // <-- ここに追加
      // 何らかの処理
    }
  }
}

これはエラーにはならなかったです。
テンプレート部分から呼び出す場合は型定義を書いて、ローカル関数は書かないという使い方ができそうです。

.riot ファイルからコード補完は効くのか

Visual Studio Code では効きませんでした。
Riot.js が HTML の中にスクリプトを書く形式なので仕方がないですね。

感想

型定義ファイルを書く分作業量は増えてしまいますが、インターフェースの恩恵を受けたいケースでは使えそうに思いました。

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2