Next.js と TypeScript で、リテラル型を学ぶ

TwitterFacebookHatena

TL;DR

この記事では、TypeScript のリテラル型という便利な機能と、それを Next.js の開発にどのように活用できるかについて詳しく見ていきます。

開発環境 バージョン
Next.js 13.4.3
TypeScript 5.0.4
Emotion 11.11.0
React 18.2.0

リテラル型とは?

リテラル型とは、TypeScript の機能の一つで、特定の決まった値のみを持つことができる型を表します。例えば、type Direction = "north" | "south" | "east" | "west"とすると、Direction型はこの 4 つの値しか受け取ることができません。

リテラル型という言葉は少し難しそうに聞こえますが、実際にはとてもシンプルな概念です。言葉の遊びで考えてみましょう。

例えば、「好きな色は何?」という質問があります。そして答えは「赤」、「青」、「緑」の中から選べるとします。これはちょっとしたクイズのようなものですね。

TypeScript のリテラル型もこれと同じ考え方です。型(つまり答え方のルール)が「赤」、「青」、「緑」のどれかと指定されています。だから、「黄色」や「紫」と答えることはできません。

他に、例えば学校の給食について考えてみましょう。

ある日の給食で、メインのおかずは「カレー」、「ハンバーグ」、「天ぷら」の 3 つから選べるとします。この選択肢は「カレー」、「ハンバーグ」、「天ぷら」のみに限られていて、「寿司」や「ピザ」は選べません。これがリテラル型の考え方と似ています。

TypeScript でのリテラル型は、特定の値しか許さない型を定義します。例えば、以下のような型を考えてみましょう。

type Lunch = 'カレー' | 'ハンバーグ' | '天ぷら'

ここで定義したLunch型は、「カレー」、「ハンバーグ」、「天ぷら」のいずれかの値しか取れません。つまり、「寿司」や「ピザ」をLunch型の値として使おうとすると、TypeScript はエラーを出してくれます。これにより、プログラムに間違った値が設定されるのを防ぐことができます。

他にも、交通信号の色を表す型を定義する例です。

type TrafficLight = 'Red' | 'Yellow' | 'Green'

このTrafficLight型では、「Red」、「Yellow」、「Green」の 3 つの値しか許されません。これは交通信号がこれら 3 つの色しか持たないからです。もし、「Blue」や「Purple」をTrafficLight型の値として使おうとすると、TypeScript はエラーを出してくれます。

また、オブジェクトのプロパティの型としてリテラル型を使うこともできます。例えば、特定のユーザーの役割を管理する場合にリテラル型を利用できます。

type UserRole = 'Admin' | 'User' | 'Guest'

type User = {
  name: string
  role: UserRole
}

const user: User = {
  name: 'Taro',
  role: 'Admin', // "Admin"、"User"、"Guest"のいずれか
}

このように、リテラル型を使うと、プログラムがどんな答えを出すべきか、またはどんな答えを受け取るべきかを厳密に決めることができます。これにより、プログラムが予期しない答え(たとえば「黄色」や「紫」)を出したり受け取ったりするのを防ぐことができます。

これはプログラムを作るときにとても役立ちます。なぜなら、プログラムは指示された通りにしか動かないからです。リテラル型を使うと、プログラムがどんな指示を受け取り、どんな結果を出すべきかを明確にすることができます。

Next.js で、リテラル型を実装

それでは、Next.js のプロジェクトでリテラル型を使ってみましょう。次の例では、リテラル型を用いてボタンコンポーネントの色を制御します。

components/Button.tsx

type ButtonProps = {
  color: 'primary' | 'secondary'
}

const Button = ({ color }: ButtonProps) => {
  return <button className={color}>{color}</button>
}

pages/index.tsx

import Button from '../components/Button'

export default function HomePage() {
  return (
    <div>
      <Button color="primary" />
      <Button color="secondary" />
    </div>
  )
}

この例では、Buttonコンポーネントはcolorプロパティを受け取ります。colorプロパティの型はリテラル型で、「primary」または「secondary」のいずれかの値を持つことができます。

リテラル型を実装

リテラル型は、コンポーネント間のコミュニケーションをより堅牢にし、バグを防ぐための強力なツールです。また、他の型と組み合わせて、更に複雑な型を構築することも可能です。

type Size = 'small' | 'medium' | 'large'
type ButtonProps = {
  color: 'primary' | 'secondary'
  size: Size
}

const Button = ({ color, size }: ButtonProps) => {
  return <button className={`${color} ${size}`}>{color}</button>
}

この例では、Size型を定義し、それをButtonProps型で使用しています。これにより、ボタンのサイズを制御する新たなsizeプロパティが追加されました。

Emotion で実装

CSS-in-JS ライブラリの一つである Emotion を使うと、リテラル型を活用して動的なスタイリングが可能になります。以下の例では、リテラル型を用いてボタンコンポーネントの色とサイズを制御します。

components/Button.tsx

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'

type Size = 'small' | 'medium' | 'large'
type ButtonProps = {
  color: 'primary' | 'secondary'
  size: Size
}

const Button = ({ color, size }: ButtonProps) => {
  const styles = css`
    background-color: ${color === 'primary' ? 'blue' : 'gray'};
    padding: ${size === 'small' ? '5px' : size === 'medium' ? '10px' : '15px'};
  `

  return <button css={styles}>{color}</button>
}

この例では、Emotion のcss関数を使って、colorsizeプロパティに基づいて動的にスタイルを生成しています。リテラル型の強力さを活用して、開発者が意図した値のみが使用されることを保証し、コードの堅牢さを向上させます。

Next.js と TypeScript で、リテラル型を学ぶ