Dev Thinking
14완료

Next.js — 가장 많이 사용하는 타입들 알아보기

2025-11-03
6분 읽기

공식문서 기반의 타입스크립트 입문기

들어가며 (Next.js에서 제공하는 주요 타입들)

Next.js로 풀스택 애플리케이션을 개발하다 보면 자연스럽게 마주치는 타입들이 있습니다. PageProps, NextRequest, Metadata 같은 것들이죠. 이 타입들은 Next.js가 제공하는 인터페이스의 일부로, 풀스택 개발을 더 안전하고 편리하게 만들어줍니다.

이번 편에서는 Next.js 개발에서 가장 많이 사용하는 타입들을 소개하고, 각 타입이 어떤 역할을 하는지 가볍게 살펴보겠습니다. 특히 개발자가 명시적으로 타입을 지정해서 사용해야 하는 PageProps, Metadata, NextRequest, NextResponse 등의 타입을 중심으로 설명하겠습니다. 타입스크립트를 처음 접하는 분들도 쉽게 따라올 수 있도록, 실제 사용 예시와 함께 설명하겠습니다.

주요 타입 소개

Next.js의 타입들은 크게 두 가지로 나눌 수 있습니다. 먼저 TypeScript가 상황에 따라 자동으로 추론하거나 적용하는 타입들을 살펴보고, 그 다음에 개발자가 명시적으로 지정해야 하는 타입들을 자세히 알아보겠습니다.

명시적으로 지정하지 않아도 되는 타입들

이 타입들은 Next.js 프레임워크가 내부적으로 자동으로 적용하거나, Hook에서 자동으로 추론되는 타입들입니다. 개발자가 직접 타입을 지정하지 않아도 Next.js가 적절한 타입을 제공합니다.

설정 타입: NextConfig

Next.js 설정 파일에서 자동으로 적용되는 타입입니다.

  • NextConfig: next.config.js 파일의 타입입니다. 설정 파일을 작성할 때는 자동으로 타입이 적용되어, 설정 객체의 속성들이 타입화됩니다.

명시적으로 지정해야 하는 타입들

이 타입들은 컴포넌트 props, 함수 파라미터, 변수 선언 등에서 직접 타입을 지정해야 합니다. Next.js 개발에서 가장 많이 작성하게 되는 타입들입니다.

페이지/컴포넌트 타입: PageProps, Metadata

App Router의 페이지 컴포넌트와 메타데이터를 정의할 때 사용하는 타입들입니다.

  • PageProps: App Router에서 페이지 컴포넌트의 props 타입입니다. export default function Page({ params, searchParams }: PageProps)처럼 컴포넌트 파라미터에서 직접 지정해야 합니다.

  • Metadata: 페이지 메타데이터의 타입입니다. export async function generateMetadata(): Promise<Metadata>처럼 함수의 반환 타입으로 직접 지정해야 합니다.

API 타입: NextRequest, NextResponse

App Router의 API Route를 구현할 때 사용하는 타입들입니다.

  • NextRequest: App Router의 API Route에서 사용하는 요청 객체 타입입니다. export async function GET(request: NextRequest)처럼 함수 파라미터에서 직접 지정해야 합니다.

  • NextResponse: App Router의 API Route에서 사용하는 응답 객체 타입입니다. return NextResponse.json()처럼 사용할 때는 자동으로 추론되지만, 변수로 사용할 때는 직접 지정해야 합니다.

이미지 타입: StaticImageData

Next.js Image 컴포넌트에서 사용하는 이미지 타입입니다.

  • StaticImageData: Next.js Image 컴포넌트의 정적 이미지 데이터 타입입니다. import heroImage from '../public/hero.jpg'처럼 이미지를 import할 때 자동으로 적용되지만, 변수 타입으로 사용할 때는 직접 지정해야 합니다.

실전 패턴 (Next.js 앱 구축하기)

이제 하나의 시나리오를 따라 각 타입들을 어떻게 적용하는지 살펴보겠습니다. 블로그 애플리케이션을 구축하면서, 각 타입의 역할을 확인해 보겠습니다.

1. PageProps로 페이지 데이터 타입화

PageProps는 App Router에서 페이지 컴포넌트의 props 타입을 정의합니다. params, searchParams 등의 URL 관련 정보를 타입화해서 동적 라우팅의 안정성을 확보할 수 있습니다.

// types/blog.ts
interface BlogPost {
  id: string;
  title: string;
  content: string;
  author: string;
  publishedAt: string;
}
 
interface BlogPageProps {
  params: { category?: string };
  searchParams: { limit?: string; sort?: string };
}
 
// app/blog/[category]/page.tsx
import { BlogPageProps } from '../../../types/blog';
 
export default function BlogCategoryPage({ params, searchParams }: BlogPageProps) {
  const category = params.category || 'all';
  const limit = parseInt(searchParams.limit || '10');
 
  return (
    <div>
      <h1>{category} 카테고리 블로그</h1>
      <p>최대 {limit}개의 포스트를 표시합니다.</p>
      {/* 실제로는 데이터 fetching 로직 */}
    </div>
  );
}

2. Metadata로 SEO 메타데이터 타입화

Metadata는 페이지의 메타데이터를 타입화합니다. Next.js 15 이상에서는 generateMetadata 함수에서도 params를 비동기로 처리해야 합니다.

// app/blog/[id]/page.tsx
import { Metadata } from 'next';
import { BlogPost } from '../../../types/blog';
 
interface BlogPostPageProps {
  params: Promise<{ id: string }>;
}
 
export async function generateMetadata({ params }: BlogPostPageProps): Promise<Metadata> {
  const { id } = await params;
 
  // 실제로는 데이터베이스에서 조회
  const post: BlogPost = {
    id: id,
    title: 'TypeScript 시작하기',
    content: 'TypeScript의 기초를 알아봅시다.',
    author: '개발자',
    publishedAt: '2024-01-01',
  };
 
  return {
    title: post.title,
    description: post.content.substring(0, 160),
    authors: [{ name: post.author }],
    openGraph: {
      title: post.title,
      description: post.content.substring(0, 160),
      type: 'article',
      publishedTime: post.publishedAt,
    },
  };
}
 
export default async function BlogPostPage({ params }: BlogPostPageProps) {
  const { id } = await params;
  return <div>블로그 포스트: {id}</div>;
}

3. NextRequest/NextResponse로 App Router API 구축

NextRequestNextResponse는 App Router의 API Route를 타입화합니다. Web API의 Request/Response를 확장한 형태로, Next.js의 기능을 안전하게 사용할 수 있습니다.

// app/api/posts/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { BlogPost } from '../../../types/blog';
 
export async function GET(request: NextRequest) {
  // NextRequest의 속성에 타입 안전하게 접근
  const searchParams = request.nextUrl.searchParams;
  const limit = parseInt(searchParams.get('limit') || '10');
 
  // 실제로는 데이터베이스에서 조회
  const posts: BlogPost[] = [
    {
      id: '1',
      title: 'TypeScript 시작하기',
      content: 'TypeScript의 기초를 알아봅시다.',
      author: '개발자',
      publishedAt: '2024-01-01',
    },
  ];
 
  // NextResponse로 타입화된 응답 반환
  return NextResponse.json({
    posts: posts.slice(0, limit),
    totalCount: posts.length,
  });
}
 
export async function POST(request: NextRequest) {
  try {
    // NextRequest의 json() 메서드 타입 안전성 보장
    const body = await request.json() as Omit<BlogPost, 'id' | 'publishedAt'>;
 
    const newPost: BlogPost = {
      ...body,
      id: Date.now().toString(),
      publishedAt: new Date().toISOString(),
    };
 
    // 실제로는 데이터베이스에 저장
    return NextResponse.json(newPost, { status: 201 });
  } catch (error) {
    return NextResponse.json(
      { error: '잘못된 요청입니다' },
      { status: 400 }
    );
  }
}

6. StaticImageData로 이미지 최적화

StaticImageData는 Next.js Image 컴포넌트의 정적 이미지 데이터 타입입니다. 이미지 최적화의 타입 안전성을 보장합니다.

// components/Hero.tsx
import Image from 'next/image';
import { StaticImageData } from 'next/image';
import heroImage from '../public/hero.jpg'; // Next.js에서 자동으로 StaticImageData 타입
 
interface HeroProps {
  image: StaticImageData;
  title: string;
}
 
function Hero({ image, title }: HeroProps) {
  return (
    <section>
      <Image
        src={image}
        alt={title}
        // StaticImageData의 속성에 타입 안전하게 접근
        width={image.width}
        height={image.height}
        priority
      />
      <h1>{title}</h1>
    </section>
  );
}
 
// 사용
<Hero image={heroImage} title="환영합니다" />

함정과 주의사항

PageProps의 함정

PageProps의 params와 searchParams는 Next.js 15 이상에서 Promise로 반환됩니다. 이를 await로 처리하지 않으면 타입 에러가 발생합니다.

// ❌ Next.js 15+에서는 params가 Promise임
interface WrongPageProps {
  params: { id: string }; // Promise<{ id: string }>이어야 함
}
 
export default function WrongPage({ params }: WrongPageProps) {
  return <div>ID: {params.id}</div>; // params는 Promise 타입
}
// ✅ Next.js 15+ 올바른 PageProps 정의
interface CorrectPageProps {
  params: Promise<{ id: string }>; // Promise로 감싸야 함
  searchParams: Promise<{ sort?: string }>;
}
 
export default async function CorrectPage({ params, searchParams }: CorrectPageProps) {
  const { id } = await params;
  const { sort } = await searchParams;
  return <div>ID: {id}, Sort: {sort}</div>;
}

Metadata의 함정

Metadata 타입은 Next.js 버전에 따라 속성이 변경될 수 있습니다. 특히 Open Graph 속성들은 선택적 속성으로, 타입 정의를 정확히 확인해야 합니다.

// ❌ 지원되지 않는 속성 사용
export async function generateMetadata(): Promise<Metadata> {
  return {
    customProperty: 'value', // Metadata 타입에 없는 속성
  };
};

NextRequest/NextResponse의 함정

App Router의 NextRequest와 NextResponse는 Web API의 Request/Response를 확장한 것이므로, Express와 다른 API를 가지고 있습니다. json() 메서드 사용 시 await를 빼먹으면 안 됩니다.

// ❌ await 생략
export async function POST(request: NextRequest) {
  const body = request.json(); // Promise 반환, await 필요
  return NextResponse.json({ error: '잘못된 요청' });
};

예상 질문(FAQ)

Q. PageProps는 어떤 상황에서 사용되나요?

PageProps는 App Router의 페이지 컴포넌트에서 URL 관련 정보를 받을 때 사용됩니다. params로 동적 경로 파라미터를, searchParams로 쿼리 파라미터를 타입화할 수 있어, 동적 라우팅 시의 타입 안전성을 보장합니다.

Q. Metadata는 언제 평가되나요?

Metadata는 서버사이드에서 평가되며, SEO와 소셜 미디어 공유를 위한 메타 태그를 생성합니다. 클라이언트 사이드 내비게이션에서는 새로운 메타데이터가 동적으로 업데이트되지 않습니다.

Q. StaticImageData는 어떻게 생성되나요?

Next.js는 public 폴더나 import된 이미지를 자동으로 StaticImageData 타입으로 변환합니다. width, height, blurDataURL 등의 속성을 포함하며, Image 컴포넌트의 최적화에 사용됩니다.

요약

Next.js의 타입들은 풀스택 개발에서 겪는 많은 문제를 해결해 줍니다. PageProps로 Next.js 15+의 Promise 기반 동적 라우팅을 타입 안전하게 처리하고, Metadata로 SEO와 소셜 미디어 메타데이터를 체계적으로 관리할 수 있습니다.

특히 NextRequest/NextResponse로 App Router API Route의 입출력 타입을 보장하고, StaticImageData로 Next.js Image 컴포넌트의 이미지 최적화를 타입화하면, 런타임 에러의 상당 부분을 컴파일 타임에 잡아낼 수 있습니다. useRouter()와 같은 Hook들은 TypeScript가 자동으로 타입을 추론해주므로, 개발자가 직접 타입을 지정할 필요가 적습니다.

참조