Next.js と TypeScript で、Rest パラメータ(残余引数)...を使う

TwitterFacebookHatena

TL;DR

このページでは、Rest パラメータの実装方法について解説しますね。一言でいうと Rest パラメータとは、JavaScript や TypeScript で関数に可変長の引数を渡すための特別な構文です。では、実際に使ってみましょう。

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

Rest パラメータ(残余引数)とは?

Rest パラメータは、JavaScript と TypeScript の関数で、引数の数が不確定な場合に使用します。Rest パラメータを使うと、複数の引数を配列としてまとめることができます。

Rest パラメータとは、関数に任意の数の引数を渡すことを可能にする JavaScript と TypeScript の特性を指します。

この特性は "残余引数" とも呼ばれ、3 つのドット(...)を引数名の前に付けることで利用できます。これにより、関数は可変数の引数を配列として受け取ることができます。

const sampleFunction = (...args: number[]) => {
  /* ... */
}

この sampleFunction は、引数の数がいくつであっても処理できます。ここで、args は配列として扱われ、関数内部で配列のメソッドを利用することができます。

また、Rest パラメータ(残余引数)は引数リストの最後にしか置くことができず、一つの関数内では一度しか使うことができません。これらは、Rest パラメータを使用する際の重要なルールです。

以下は、基本的な Rest パラメータの使用方法です。

const sum = (...numbers: number[]): number => {
  return numbers.reduce((prev, current) => prev + current, 0)
}

console.log(sum(1, 2, 3, 4)) // 10

上記の sum 関数は、...numbers: number[]という形で Rest パラメータを定義しています。この ...numbersは、関数 sumに渡された任意の数の引数をnumbersという配列にまとめてくれます。この関数は、1, 2, 3, 4といった任意の数の引数を受け取り、それらをすべて足し合わせた結果を返します。

Rest パラメータは関数の引数リストの最後に書く

Rest パラメータは関数の引数リストの最後にある必要があります。

Rest パラメータは、その位置から関数の最後までのすべての引数を配列にまとめる役割を持っています。そのため、Rest パラメータの後に他の引数を置くことはできません。以下のようなコードは無効です。

// これは無効です。
const invalidFunction = (...args: number[], anotherArg: string) => {
  // do something
}

これを TypeScript で実行しようとすると、コンパイラは次のようなエラーメッセージを出力します:

A rest parameter must be last in a parameter list.

これは、「Rest パラメータはパラメータリストの最後でなければならない」という意味です。

Rest パラメータについて理解する際に注意すべき点

Rest パラメータについて理解する際に注意すべき点としては以下の 2 つがあります。

  1. Rest パラメータは引数リストの最後にしか配置できません。
  2. Rest パラメータは一つの関数内で一度だけしか使用できません。

分かりやすい例を一つ挙げましょう。以下は、与えられた全ての数字を合計する関数を Rest パラメータを使って実装したものです。

type NumericArray = number[]

const sum = (...numbers: NumericArray) => {
  let total = 0
  for (const num of numbers) {
    total += num
  }
  return total
}

console.log(sum(1, 2, 3, 4)) // 10を出力します。

この例では、sum 関数は任意の数の引数を取ることができます。これらの引数はすべて numbers 配列に格納され、それを用いて総和を求めています。

なお、Rest パラメータは TypeScript の特性であり、JavaScript や他の多くのプログラミング言語でも使われている特性です。これにより関数が可変長の引数を柔軟に扱うことができ、コードの再利用性と可読性を向上させることができます。

Next.js で、Rest パラメータを実装

それでは Next.js と TypeScript を使って、Rest パラメータの実装例を見てみましょう。今回は、複数の CSS スタイルを結合する mergeStyles関数を作成します。

components/mergeStyles.tsx:

import { css, SerializedStyles } from '@emotion/react'

type Styles = SerializedStyles | SerializedStyles[]

const mergeStyles = (...styles: Styles[]): SerializedStyles => {
  return css(styles.flat())
}

export default mergeStyles

この mergeStyles関数では、...styles: Styles[]という形で Rest パラメータを受け取ります。これにより、引数として複数のスタイルオブジェクトを受け取ることができます。そして、styles.flat()により、ネストされた配列もフラットにすることができます。

Emotion での利用例

それでは、作成した mergeStyles関数を Emotion で利用してみましょう。Next.js のコンポーネントで、複数のスタイルを結合して適用する例を示します。

components/MyComponent.tsx:

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

type Props = {
  isActive: boolean
}

const MyComponent = ({ isActive }: Props) => {
  const activeStyle = css`
    color: blue;
  `

  const baseStyle = css`
    font-size: 16px;
  `

  return <div css={mergeStyles(baseStyle, isActive && activeStyle)}>Hello, World!</div>
}

export default MyComponent

このコンポーネントでは、mergeStyles(baseStyle, isActive && activeStyle)という形で、mergeStyles関数を利用しています。isActivetrueの場合、activeStyleが適用され、falseの場合は適用されません。これにより、動的にスタイルを結合することができます。

API ルートの動的パラメータ

Next.js では、API ルートでも Rest パラメータを活用することができます。これにより、動的な URL パラメータを扱うことが可能になります。以下に、その例を示します。

pages/api/user/[...username].ts:

import type { NextApiRequest, NextApiResponse } from 'next'

type Params = {
  username: string[]
}

type Data = {
  username: string
}

const handler = (req: NextApiRequest, res: NextApiResponse<Data>) => {
  const { username } = req.query as Params

  res.status(200).json({ username: username.join('/') })
}

export default handler

この API ルートでは、[...username]という形で Rest パラメータを定義しています。この形式を使うことで、/api/user/john/doeのような URL が全てこの API ルートにマッチします。そして、usernameパラメータは['john', 'doe']という配列として取得できます。

Next.js と TypeScript で、Rest パラメータ(残余引数)...を使う