【React × TypeScript】propsで渡すデータに列挙型(enums)をつける方法

##要約
こう書いてもいいですが

```typescript
const Tags = [ "React", "Redux Toolkit", "Firebase", "Tailwind CSS" ]
```
TypeScriptで列挙型(enums)をつけてみましょうという話です。

```typescript
enum TagTypes = {
  react = "React",
  toolkit = "Redux Toolkit",
  firebase = "Firebase",
  tailwind = "Tailwind CSS",
}
export default TagTypes;
```

```typescript
import TagTypes;

const Tags = [
  TagTypes.react,
  TagTypes.toolkit,
  TagTypes.firebase,
  TagTypes.tailwind,
]
```
<hr/>
##やったこと
![スクリーンショット 2021-04-02 19.51.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1028795/f477863e-d6f8-8422-867c-759121c15dbe.png)
よくある成果物一覧ページをNext.jsで作りました。
画像やリンク、タグ名などのpropsをPortfolioItemコンポーネントにまず渡して、その中でTagコンポーネントにタグ名を渡しています。
その際、ある方のGithubコードを参考に、タグに列挙型をつけることができたので共有します。
##方法
①まずTagTypes.tsファイルを`root/src/enums/`に作ります。
タグは他のPortfolioItemコンポーネントでも利用されるのでズラーっと定義しておきます。

```typescript
enum TagTypes = {
  html = "HTML",
  css = "CSS",
  jquery = "jQuery",
  javascript = "JavaScript",
  react = "React",
  toolkit = "Redux Toolkit",
  next = "Next.js",
  rails = "Rails",
  firebase = "Firebase",
  rspec = "RSpec",
  heroku = "Heroku",
  bootstrap = "Bootstrap",
  tailwind = "Tailwind CSS",
  vercel = "Vercel",
}

export default TagTypes; //忘れずに
```
②次にこのTagTypes.tsをインポートして、キーを指定する形でタグを設定します。
↓Portfolio.tsx

```typescript
import type { VFC } from "react";
import Head from "next/head";
import Layout from "src/components/Layout";
import PortfolioItem from "src/components/PortfolioItem";
import TagTypes from "src/enums/TagTypes";  // TagTypesをインポート。

const PORTFOLIO_ITEMS = [
  {
    href: "https://moyong-front.web.app/",
    src: "/workoutJournal.png",
    name: "Workout Journal",
    created_at: "2021/3",
    tags: [
      TagTypes.react,  // "React"のような文字列の代わりに、先ほど定義したTagTypesのキーを指定する。 
      TagTypes.toolkit,
      TagTypes.firebase,
      TagTypes.tailwind
    ],  
    text: [
      "日々の筋トレを記録できるアプリです。",
      "主な機能としては、ログイン機能、投稿機能、コメント機能、GitHubカレンダー機能です。",
      "構成は React / Redux Toolkit / Typescript / Firebase です。",
      "UIはTailwind CSSとMaterial UIを使用しています。",
    ],
  },
];
const Works: VFC = () => {
  return (
    <>
      <Head>
        <title>Portfolio | MO4g-DEV</title>
      </Head>
      <Layout>
        <div className="flex flex-col justify-center items-center">
          {PORTFOLIO_ITEMS.map((item) => (
            <PortfolioItem
              href={item.href}
              src={item.src}
              name={item.name}
              created_at={item.created_at}
              tags={item.tags} // ここで渡す。
              text={item.text}
            />
          ))}
        </div>
      </Layout>
    </>
  );
};
export default Works;
```
③ここでもTagTypes.tsをインポートして、PROPS型を定義して、子のTechTagコンポーネントにタグ名を渡します。
↓PortfolioItem.tsx

```typescript
import React, { VFC } from "react";
import Image from "next/image";
import TechTag from "src/components/TechTag";
import ScheduleIcon from "@material-ui/icons/Schedule";
import TagTypes from "src/enums/TagTypes"; // TagTypesをインポート。
interface PROPS {
  href: string,
  src: string,
  name: string,
  created_at: string,
  tags: TagTypes[], // enumsをつけないならstring[]となりますが、TagTypes[]とした方がより厳密。
  text: string[],
}
const PortfolioItem: VFC<PROPS> = (props) => {
  const { href, src, name, created_at, tags, text } = props;
  return (
    <div className="flex flex-col w-11/12 my-5 xl:py-5 xl:px-10 border shadow-md xl:flex-row">
      <a
        className="flex justify-center items-center mt-5 xl:mt-0 xl:w-2/5"
        href={href}
        target="_blank"
        rel="noopener noreferrer"
      >
        <Image src={src} width={450} height={270} />
      </a>
      <div className="flex flex-col justify-center items-center m-5 xl:w-3/5 xl:justify-start xl:items-start">
        <h1 className="text-lg text-black xl:text-2xl font-bold">{name}</h1>
        <p className="text-sm text-black xl:mt-2">
          <ScheduleIcon className="text-sm mx-1" />
          {created_at}
        </p>
        <div className="flex mt-2">
          {tags.map((tag) => (
            <TechTag name={tag} > // タグ名をnameという名前でTechTagコンポーネントに渡す。
          ))}
        </div>
        <div className="mt-2 sm:w-4/5 md:2/3 xl:w-full">
          {text.map((row) => (
            <p className="text-sm text-black xl:text-base xl:my-1">{row}</p>
          ))}
        </div>
      </div>
    </div>
  );
};
export default PortfolioItem;
```
④あとは渡されたタグ名を表示します。
↓TechTag.tsx

```typescript
import { VFC } from "react";

interface  PROPS {
  name: string;
}

const TechTag: VFC<PROPS> = (props) => {
  const { name } = props;
  return <div className="text-xs p-1 mx-1 rounded-sm shadow-inner bg-tag text-white sm:text-sm font-medium">{name}</div>;
}

export default TechTag;
```
##なぜやるのか
今回定義したTagTypes型は、例として以下のタグが同時に存在しないことを保証してくれます。
・Redux Toolkit
・Redux Tooklit （タイポ）
・Redux ToolKit （toolkitのkが大文字）
いずれも文字列なので、string型では統一しきれないわけです。

(・x・ ).o0○（分かりやすい文章書きたい...）
たとえ記事に関係ないことでも、疑問等コメントしていただけると嬉しいです！