Astro で details 要素に name 属性を使うと型チェックでエラーになる件を解決する

Astro で details 要素に name 属性を使ったら、型チェックでエラーになったので、対処した件を備忘録がわりにメモしておきます。今後、Astro のバージョンアップで問題なくなる可能性もあるので運悪くこの問題にぶち当たった人だけどうぞ。

たまたまぶち当たったので備忘録。

前提と経緯

  • 最新の HTML Standard において、details 要素に name 属性が使用できる
  • Astro (v.4.2.1) で details 要素に name 属性を使ったら、astro check で怒られた
  • HTMLAttributes 型を拡張して対応した

details 要素の仕様

details 要素の仕様は下記ですが、name 属性が使用できることが確認できます。確か昨年の 10 月くらいにこの修正がマージされたのをみた記憶があるので最近ですが。

で、この記事執筆時点で Firefox 以外の主要ブラウザではサポートされています。

details 要素に name 属性によって同一の名前を付与することで、複数の details 要素をグループ化し、グループ内の details 要素が 1 つ開いたら、他を閉じる、といった、所謂排他的動作をさせることが可能です。

例えば下記のように記述することで、「HTML」 を開いた状態で、「CSS」 の方を開くと、「HTML」 が自動的に閉じてくれます。

<details name="content-menu">
  <summary>HTML</summary>
  <ul>
     <li><a href="#">HTML5 タグリファレンス</a></li>
     <li><a href="#">HTML5 の基礎知識</a></li>
     <li><a href="#">HTML5 に関するリンク集</a></li>
  </ul>
  </details>
  <details name="content-menu">
  <summary>CSS</summary>
  <ul>
     <li><a href="#">CSS リファレンス</a></li>
     <li><a href="#">CSS の基礎知識</a></li>
     <li><a href="#">CSS に関するリンク集</a></li>
  </ul>
</details>

astro check で怒られる件

で、普通に details 要素に name 属性を書いたら、astro check 時に、

error ts(2322): Type '{ children: any[]; name: string; }' is not assignable to type 'DetailsHTMLAttributes'.
  Property 'name' does not exist on type 'DetailsHTMLAttributes'.

 <details name="example">

がでて怒られましたとさ。

HTMLAttributes 型を拡張する

Astro はマークアップが有効な HTML の属性を使用しているか確認するために、HTMLAttributes 型を提供してくれていますが、この中で details 要素に対する name 属性が定義されていないので型チェックでエラーになります。ということで name 属性を追加することで回避しました。

プロジェクトのルートディレクトリに custom-attributes.d.ts を新規作成し、下記の内容で保存します。これだけ。

// details 要素に name 属性を付与できるように型定義
declare namespace astroHTML.JSX {
    interface IntrinsicElements {
        details: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
            name?: string;
        };
    }
}

恐らく、今後の Astro のアップデートで勝手に解決するとは思いますが、とりあえずの回避措置として。

ちなみに下記のようにして、全要素に独自の属性を追加することもできますが、あまり適用範囲が広すぎるのもあれなので、前述の通り、details 要素のみ対象にするようにしています。

declare namespace astroHTML.JSX {
  interface HTMLAttributes {
    'foo'?: number;
    'bar'?: string;
  }
}

記事をここまで御覧頂きありがとうございます。
この記事が気に入ったらサポートしてみませんか?