メインコンテンツまで移動する

Astro の Polymorphic を使う時に any にしないためのデフォルト値

  • 公開日

Akira Web デザイナー

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.propsany になります。

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 } : {});

const { as: Tag = 'button', ...props } = Astro.props;
---

<Tag class:list={'btn'} {...props}>
  <slot />
</Tag>

フォローする