👌

Ionic AngularのAttribute型判定をするESLintルールをつくった話

に公開

Ionic Angularのテンプレートで、以下のような要素を書いていませんか?

<ion-item button="true"></ion-item>
<ion-progress-bar value="50"></ion-progress-bar>
<ion-radio labelPlacement="center"></ion-radio>

一見正しく見えるこのコードですが、実はTypeScriptの型情報上ではエラーがでます。なぜなら、Ionicコンポーネントの多くの属性は文字列ではなく、boolean、number、または特定の文字列リテラル型を期待しているからです。

HTMLとJSフレームワークの違い

通常のHTMLでは、すべての属性値は文字列として扱われます。Ionicコンポーネントでも同様で、例えば:

<!-- Ionicコンポーネント:文字列として処理される -->
<ion-item button="true" disabled="false">
<ion-progress-bar value="50">

この場合、Ionic Frameworkが button="true" という文字列を受け取り、内部で適切な型(boolean)に変換します。

しかし、Angularを使用している場合、components.d.ts によって各コンポーネントの属性に厳密な型定義が期待されています:

// @ionic/core/dist/types/components.d.ts の例
interface IonItem {
  button?: boolean;  // boolean型を期待
  disabled?: boolean;
  lines?: 'full' | 'inset' | 'none';  // 特定の文字列リテラル型を期待
}

TypeScriptでは、この型定義に基づいて型チェックが行われるため、以下のような問題が発生します:

<!-- TypeScriptの型チェックでエラーになる -->
<ion-item button="true">  <!-- string "true" ≠ boolean true -->
<ion-item lines="invalid">  <!-- "invalid" は許可された値ではない -->

WebStormの最新版では、このような型チェックエラーが表示されるようになりました:

このTypeScriptの型チェックはビルド済みのIonicコンポーネントに対するものですので、Angularのビルドを妨げることはありません。しかし、開発者にとって型エラーが表示されることで、正しいコードの書き方を理解する必要が生まれました。
そこで、この問題を事前に検出して自動修正するESLintルールを作成しました。

ESLintルールで一発解決

@rdlabo/rules/ionic-attr-type-check というESLintルールを開発し、この問題を根本的に解決しました。ビルドを妨げないということはエラーを一覧で得ることができず、エラーと修正はIDE上で目視で確認しないといけなくて現実的ではなかったんですよね。

主な機能

1. 自動的な型検出

ルールは実行時に @ionic/core/dist/types/components.d.ts を読み込み、各Ionicコンポーネントの属性型を動的に解析します。これにより:

  • すべてのIonicコンポーネントに対応:ion-itemion-buttonion-modalなど、すべてのコンポーネントを網羅
  • 型の自動判別:boolean、number、string literal unionを自動識別
  • 将来のIonicバージョンへの対応:型定義ファイルから動的に読み込むため、新しいコンポーネントや属性にも自動対応

2. 検証・修正対応状況

ルールは以下の型を検証し、エラーを表示します:

Boolean属性

<!-- ❌ Before -->
<ion-item button="true" disabled="false"></ion-item>
<ion-toggle checked="true"></ion-toggle>

<!-- ✅ After -->
<ion-item [button]="true" [disabled]="false"></ion-item>
<ion-toggle [checked]="true"></ion-toggle>

Number属性

<!-- ❌ Before -->
<ion-progress-bar value="50" buffer="75"></ion-progress-bar>
<ion-range min="0" max="100"></ion-range>

<!-- ✅ After -->
<ion-progress-bar [value]="50" [buffer]="75"></ion-progress-bar>
<ion-range [min]="0" [max]="100"></ion-range>

String Literal Union属性

<!-- ❌ エラーが表示される -->
<ion-item lines="invalid"></ion-item>
<ion-radio labelPlacement="center"></ion-radio>

<!-- ✅ 正しい値 -->
<ion-item lines="full"></ion-item>
<ion-radio labelPlacement="start"></ion-radio>

3. 自動修正機能

現在のバージョンでは、boolean・number属性に対して自動修正(auto-fix)機能が利用できます:

npx eslint --fix src/**/*.html

なお、string literal union属性についてはエラー検出のみ対応しています。

使用方法

インストール

npm install @rdlabo/eslint-plugin-rules --save-dev

設定

ESLint設定ファイル(eslint.config.js)に以下を追加:

import rdlabo from '@rdlabo/eslint-plugin-rules';

export default [
  {
    files: ['*.html'],
    plugins: {
      '@rdlabo/rules': rdlabo,
    },
    rules: {
      '@rdlabo/rules/ionic-attr-type-check': 'error',
    },
  }
];

これだけで、HTMLテンプレートファイル内のIonicコンポーネントの属性型チェックが有効になります。

実際の動作例

開発中に以下のようなコードを書くと:

<ion-item button="true" lines="true">
  <ion-label>設定</ion-label>
</ion-item>
<ion-progress-bar value="50"></ion-progress-bar>

ESLintが以下のようなエラーを表示します:

error  Attribute 'button' expects boolean type, use property binding [button]="true"  @rdlabo/rules/ionic-attr-type-check
error  Attribute 'lines' expects string literal type, use valid value like "full", "inset", or "none"  @rdlabo/rules/ionic-attr-type-check
error  Attribute 'value' expects number type, use property binding [value]="50"  @rdlabo/rules/ionic-attr-type-check

--fix オプションを使用すると、自動的に以下のように修正されます:

<ion-item [button]="true" lines="full">
  <ion-label>設定</ion-label>
</ion-item>
<ion-progress-bar [value]="50"></ion-progress-bar>

技術的な実装のポイント

動的型解析の仕組み

ルールは以下の手順で動作します:

  1. 型定義ファイルの読み込み:@ionic/core/dist/types/components.d.ts を解析
  2. コンポーネント情報の抽出:各コンポーネントの属性とその型情報を取得
  3. テンプレート解析:HTMLテンプレート内のIonicコンポーネントを検出
  4. 型チェック実行:属性値と期待される型を比較
  5. 修正提案の生成:適切なプロパティバインディングまたは正しい値を提案

パフォーマンス最適化

  • キャッシュ機能:型情報は初回読み込み時にキャッシュし、パフォーマンスを向上
  • 必要時のみ解析:Ionicコンポーネントが検出された場合のみ型チェックを実行
  • 効率的な文字列処理:正規表現を使用した高速なテンプレート解析

実際の開発現場での効果

このルールを導入したプロジェクトでは、以下のような効果が確認されています:

開発効率の向上

  • コードレビュー時間の短縮:型関連のエラーを事前に検出できるため、レビューでの指摘が減少
  • デバッグ時間の削減:実行時エラーを事前に防げるため、デバッグにかかる時間が大幅に短縮

コード品質の向上

  • 一貫したコーディングスタイル:チーム全体で統一されたプロパティバインディングの使用
  • TypeScript型安全性の向上:コンパイル時エラーの削減

学習コストの削減

  • 新規参加者への教育効果:ESLintエラーを通じて、Ionicの正しい使い方を自然に学習
  • ドキュメント参照の削減:各属性の正しい型をエラーメッセージで確認可能

まとめ

Ionic Angularでの開発において、属性の型ミスマッチは頻繁に発生する問題でした。今回開発した @rdlabo/rules/ionic-attr-type-check ルールにより:

  1. 自動検出:Ionicコンポーネントの属性型(boolean・number・string literal union)を自動的に検証
  2. 自動修正:ESLintの --fix オプションで一括修正が可能
  3. 動的対応:型定義ファイルから動的に属性情報を取得
  4. 将来対応:Ionicの新バージョンにも自動的に対応

これにより、開発者はより安全で効率的なIonic Angularアプリケーションを構築できるようになりました。

チームでIonic Angularを使用している場合は、ぜひ導入を検討してみてください。コード品質の向上と開発効率の改善を実感できるはずです。

詳細な情報や最新のアップデートについては、GitHub リポジトリをご覧ください。

Discussion