Next.js 15에서 발생한 타입 에러

송연지·2024년 11월 30일
0

트러블슈팅

목록 보기
11/32

Next.js 15에서 발생한 타입 에러와 해결 과정

문제 상황

Next.js 15 버전에서 동적 라우팅([id])과 API 응답 처리 시 여러 타입 에러가 발생했습니다.

1. 동적 라우팅 타입 에러

// 에러 메시지
Error: Route "/items/[id]" used `params.id`. `params` should be awaited before using its properties.

2. API 응답 타입 에러

Type error: Property 'id' does not exist on type 'ApiResponse<Item>'.

발생 원인

1. Next.js 15의 변경된 동적 라우팅 처리

페이지 파라미터가 Promise 타입으로 변경됨
params 객체 처리 방식의 변화

2. API 응답 타입과 실제 데이터 구조의 불일치

interface ApiResponse<T> {
  data: T;
  statusCode: number;
  message: string;
}

// 실제 받은 응답 구조
{
  id: number;
  tenantId: string;
  name: string;
  memo?: string;
  imageUrl?: string;
  isCompleted: boolean;
}

해결 과정

1. 동적 라우팅 수정

// src/app/items/[id]/page.tsx
interface PageProps {
  params: { id: string };
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
  return {
    title: `Item ${params.id}`,
  };
}

export default function ItemDetailPage({ params }: PageProps) {
  const id = Number(params.id);

  if (isNaN(id)) {
    return notFound();
  }

  return <ItemDetail id={id} />;
}

2. API 응답 처리 수정

// src/hooks/useItemDetail.ts
export function useItemDetail(id: number) {
  const [item, setItem] = useState<Item | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const fetchItem = useCallback(async () => {
    if (!id) return;

    try {
      setLoading(true);
      setError(null);
      const response = await itemApi.getItemById(id);
      
      if (!response || !response.id) {
        throw new Error('유효하지 않은 응답입니다.');
      }

      console.log('Fetched item:', response);
      setItem(response);
    } catch (err) {
      console.error('Fetch error:', err);
      setItem(null);
      setError(err instanceof Error ? err.message : '항목을 불러오는데 실패했습니다.');
    } finally {
      setLoading(false);
    }
  }, [id]);

  useEffect(() => {
    fetchItem();
  }, [fetchItem]);

  // ... 나머지 코드
}

3. API 함수 수정

// src/lib/api.ts
export const itemApi = {
  getItemById: async (id: number) => {
    const response = await api.get<Item>(`/${TENANT_ID}/items/${id}`);
    return response.data;
  },
  // ... 다른 메서드들
};

문제 해결 방법

타입 정의 일치시키기

// types/item.ts
export interface Item {
  id: number;
  tenantId: string;
  name: string;
  memo?: string;
  imageUrl?: string;
  isCompleted: boolean;
}

응답 처리 단순화

API 응답 래퍼 타입을 제거하고 직접 Item 타입 사용
불필요한 중첩 구조 제거

에러 처리 개선

try {
  const response = await itemApi.getItemById(id);
  if (!response) throw new Error('데이터를 찾을 수 없습니다.');
  setItem(response);
} catch (err) {
  setError(err instanceof Error ? err.message : '오류가 발생했습니다.');
}

주의사항

1. 타입 체크 비활성화는 임시 방편

// next.config.js
const nextConfig = {
  typescript: {
    ignoreBuildErrors: true, // 권장하지 않음
  }
}

2. API 응답 구조 확인

  • 서버 응답 구조를 명확히 파악
  • 타입 정의와 실제 데이터 일치 확인

3. Next.js 버전 호환성

  • 버전 업그레이드 시 breaking changes 확인
  • 필요한 마이그레이션 작업 수행

학습한 점

  • Next.js 15에서 동적 라우팅 처리 방식 변경
  • TypeScript 타입 시스템의 중요성
  • API 응답 처리 시 타입 안정성 확보 방법
  • 에러 처리와 상태 관리의 중요성

ㅎㅎㅎ... 버전을 잘봅자..ㅠㅅㅠ 두시간동안 고생하지말고,....

참고 자료

  • Next.js Documentation
  • TypeScript Handbook
profile
프론트엔드 개발쟈!!

0개의 댓글