Next.js と TypeScript で、オプションパラメーター(?)を使う

TwitterFacebookHatena

TL;DR

TypeScript では、関数の引数の中に「?」を入れることで、オプションパラメーター(オプション引数)を定義できます。この記事では、オプションパラメーターの活用方法についてお話しします。一言で言えば、オプションパラメーターとは、関数に渡す引数が必須ではなく、省略可能であるという意味です。それでは詳しく見ていきましょう。

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

オプションパラメーターとは?

TypeScript では、関数の引数を定義する際に、それが必須なのか、任意なのかを決定できます。これがオプションパラメーターです。TypeScript ではオプションパラメーターは引数名の後に?を追加することで指定できます。例えば、以下のような形になります。

function greeting(name: string, age?: number) {
  if (age) {
    return `Hello, ${name}. You are ${age} years old.`
  }
  return `Hello, ${name}.`
}

上記のコードでは、greetingという関数が定義されています。この関数は 2 つの引数を受け取ります。nameは必須の引数で、ageはオプションです。つまり、ageは指定しなくてもこの関数は正常に動作します。

この特性を利用すれば、関数が柔軟に動作するように設計できます。例えば、何らかの API へのリクエストを送る関数を考えてみてください。その API が複数のオプションパラメーターを受け入れるとします。関数内でそれらのパラメーターをオプションとして扱うことで、API へのリクエストを柔軟にコントロールすることができます。

オプションパラメーターの順番

通常、TypeScript(または JavaScript)ではオプション引数は最後に記述する必要があります。これは、関数が引数を順番に読み取るためで、もし必須の引数がオプション引数の後に来てしまうと、オプション引数が省略された時にどの引数が省略されたのかが不明確になります。そのため、一般的にはオプション引数は最後に配置されます。

たとえば以下の関数は、エラーとなります。

function greeting(age?: number, name: string) {
  // ここでエラーが発生します。
}

なぜなら、name 引数は必須ですが、age 引数が省略可能なため、greeting("John")というような呼び出し方が可能かどうかが曖昧になってしまうからです。

しかし、オブジェクトを引数に取る場合はこの制限はなくなります。その場合、オプションパラメーターと必須パラメーターはどの順番でも構いません。

type Options = {
  name: string
  age?: number
}

function greeting({ name, age }: Options) {
  // 順番は問題ありません
}

上記のコードでは、nameは必須であり、ageはオプションですが、それぞれがオブジェクトのプロパティとして指定されているため、引数としての順序は問類ありません。

Next.js で、オプションパラメーターを活用

Next.js のコンテキストを考えて、オプションパラメーターの活用例を見てみましょう。以下のコードは、Next.js のページコンポーネントの一部です。

ファイル名: pages/index.tsx

import React from 'react'

type Props = {
  title?: string
  message?: string
}

const HomePage = ({ title = 'Welcome', message = 'This is home page' }: Props) => {
  return (
    <div>
      <h1>{title}</h1>
      <p>{message}</p>
    </div>
  )
}

export default HomePage

このHomePageコンポーネントはtitlemessageという 2 つのプロパティを受け取ります。しかし、どちらのプロパティもオプションで、デフォルト値が設定されています。このようにオプションパラメーターは、デフォルト値と組み合わせることで非常に有用なツールになります。

オプションパラメーターを実装

更に深く理解するために、よりテクニカルな実装例を見てみましょう。以下の例では、API からデータを取得する関数を定義しています。

type ApiFetchOptions = {
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
  headers?: { [key: string]: string }
  body?: any
}

async function fetchData(url: string, options?: ApiFetchOptions) {
  const response = await fetch(url, options)
  const data = await response.json()
  return data
}

上記のfetchData関数は 2 つの引数を受け取ります。urlは API のエンドポイントで、これは必須です。しかし、options引数はオプションで、特にメソッド、ヘッダー、ボディなど、fetch 関数に与えることができるオプションを表現しています。

この関数を使って、データを取得する方法は多く、次のような形になります。

const data1 = fetchData('https://example.com/api/data')

const data2 = fetchData('https://example.com/api/data', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ key: 'value' }),
})

このように、オプションパラメーターは、関数がさまざまな状況に対応できるようにするための強力なツールと言えるでしょう。本記事を通じて、その基本的な使用法と Next.js と TypeScript における具体的な使用例を理解できたことと思います。

Next.js と TypeScript で、オプションパラメーター(?)を使う