Astro の Polymorphic を使う時に any にしないためのデフォルト値
Astro には、複数の HTML 要素を受け入れ可能なコンポーネントを作る時に便利な TypeScript の型の Polymorphic があります。例えば、<a>
と <button>
のいずれかが HTML 要素のボタンコンポーネントを作る時などに役立ちます。
この Polymorphic の例として、ドキュメントにはこのように書かれています。
--- import type { HTMLTag, Polymorphic } from 'astro/types'; type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }>; const { as: Tag, ...props } = Astro.props; --- <Tag {...props} />
ただ、この例のままでは Astro.props
が any
になります。

any
にしないためには、Astro.props is type as any when use Polymorphic にあるようにデフォルト値が必要です。button
をデフォルト値に設定してみます。
--- import type { HTMLTag, Polymorphic } from 'astro/types'; type Props<Tag extends HTMLTag = 'button'> = Polymorphic<{ as: Tag; }>; const { as: Tag = 'button', ...props } = Astro.props; --- <Tag {...props} />
これで Astro.props
の型はこのようになります。
(property) props: Props<"button">
余談ですが、HTMLTag
は全ての HTML 要素の型です。私は安全な HTMLTag
は使いつつ、必要な HTML 要素を Extract
で抽出するのを好んでいます。ボタンコンポーネントであれば <a>
と <button>
を抽出します。また、<a>
の場合は href
属性を必須にするように作っています。
--- import type { HTMLTag, Polymorphic } from 'astro/types'; type Props<Tag extends Extract<HTMLTag, 'a' | 'button'> = 'button'> = Polymorphic<{ as: Tag; }> & (Tag extends 'a' ? { href: string | URL } : object); const { as: Tag = 'button', ...props } = Astro.props; --- <Tag class:list={'btn'} {...props}> <slot /> </Tag>