0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.jsの動的ルートで型安全にパラメータを扱う方法

Posted at

はじめに

Next.jsで動的ルートを使う際、URLパラメータはstring | undefined型として受け取りますが、実際のアプリケーションでは特定の値のみを許可したいケースが多く存在します。
しかし、型安全性が担保されていないと不正な値でも実行時エラーにならないため、バグの原因となってしまいます。
そのため、動的ルートパラメータの型安全性を確保する仕組みが必要になります。

問題

ECサイトで商品カテゴリページを作る場面を想定して下さい。
/products/electronics/products/books/products/clothingのようなURLで、カテゴリ別に商品を表示したいので、Next.jsの動的ルートを使って実装します。

// pages/products/[category].tsx
export default function ProductsPage() {
  const params = useParams<{ category: string }>()

  // params.category に応じて商品を表示
  return <ProductList category={params.category} />
}

ここで、Next.jsの動的ルート[category]で受け取ったパラメータはstring | undefined型ですが、実際は特定の値('electronics''books''clothing')のみが有効なので、型安全ではなくなってしまいます。

// ❌ 不正なURLでもエラーにならない
// /products/toys にアクセスした場合
const category = params.category // "toys"
setCurrentCategory(category) // 意図しない値がセットされる

// ❌ 実行時エラーの原因になりうる
const apiUrl = `/api/products/${category}` // 存在しないAPIエンドポイント

解決策

as constと型ガードを使って型安全にチェック

export const CategoryValues = {
  Electronics: 'electronics',
  Books: 'books',
  Clothing: 'clothing',
} as const

export type Category = (typeof CategoryValues)[keyof typeof CategoryValues]

export const isCategory = (param: string | undefined): param is Category => {
  return param
    ? Object.values(CategoryValues).some((value) => value === param)
    : false
}

使用例

const params = useParams<{ category: string }>()
const category = isCategory(params.category) ? params.category : 'electronics'

setCurrentCategory(category)

まとめ

数行のコードを追加することで、型安全性を確保できるようになりました。

この実装パターンは他の動的ルート(ユーザーロール、ステータスなど)にも応用できるので必要に応じて実装をしてみて下さい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?