
엄청 자주 만들었던 투두리스트를 Next.js로 만들기 시작했다. Tailwind로 스타일링하는 것에 점차 익숙해지는 듯싶더니, 데이터 가져오는 부분에서 타입 에러가 발생했다. 타입스크립트 너무 어렵다...
분명히 배운대로 잘 작성한 것 같은데 dev 모드에서는 데이터 가져오는 것부터 UI에 뿌려지는 것까지 잘 되다가 npm run build 하니까 아래와 같은 에러가 뜨면서 빌드에 실패하는 것이다.
에러메시지가 너무 길고 복잡해서 눈에 잘 들어오지도 않는다. 그런데 일단 api 부분에서 타입 에러가 난 것은 확실해 보인다. 잘은 모르겠지만 never[]가 할당될 수 없기 때문에 그렇다는 것 같다.
never[]는 함수나 표현식에서 반환되는 배열의 타입 중 하나로, 절대로 값을 포함하지 않는 배열을 나타낸다.
never를 반환할 수 있다.never이다.정리해보면, 예상치 못한 상황에서 함수나 표현식이 중단되면서 아무 값도 갖고 있지 않는 never가 반환되는 것이다. 즉, never[]가 왜 반환되는지 원인을 찾아보고, 그렇게 되지 않도록 조치를 취해야 이 오류를 해결할 수 있겠다.
import { TodosList } from '@/app/types';
export async function GET(request: Request) {
const response = await fetch(`http://localhost:4000/todos`);
const todosList: TodosList[] = await response.json();
if (!todosList) {
return new Response('Todos 정보를 찾을 수 없습니다.', { status: 404 });
} else if (todosList.length === 0) {
return []; // <------ 바로 이 부분 때문인 것 같다.
}
return Response.json({ todosList: todosList });
}
fetch해서 받은 response를 정리해서 todosList에 담아두는 내용이다. todosList가 없는 경우 잘못된 요청이므로 404 응답을 반환해준다.
서버로부터 제대로 response를 받아오긴 했지만 작성된 게시글이 아무 것도 없는 등의 이유로 데이터가 없는 경우에 대한 예외처리를 나름 해주고 싶었다. 내 딴에는 어쨌든 Todos[] 타입에 맞게 배열을 반환해 주어야 한다는 생각을 했기 때문에 데이터가 없더라도 빈 배열이라도 반환해 주도록 return []로 작성해주었는데, 이 곳이 문제가 되었던 것 같다.
- 챗지피티 선생님의 설명:
GET함수는Promise<Response>를 반환해야 하는데, 배열을 반환하도록 작성되어 있다. 이렇게 되면TypeScript에서는 배열을Promise<Response에 할당할 수 없다고 판단하여never[]를 반환하게 된다.
import { CompanyInfo } from '@/app/types';
export async function GET(request: Request): Promise<Response> {
try {
const response = await fetch(`http://localhost:4000/companyInfo`);
const data: CompanyInfo = await response.json();
if (!data || Object.keys(data).length === 0) {
return new Response('회사 정보가 없습니다.', { status: 404 });
}
return new Response(JSON.stringify({ data }), { status: 200 });
} catch (error) {
console.error('에러 발생', error);
return new Response(`서버 에러`, { status: 500 });
}
}
우선 GET함수의 반환 데이터 타입을 Promise<Response>로 명시해주었다. 그리고 비동기 함수인만큼 try/catch문을 사용하여 서버와 통신 시 에러가 발생했을 경우를 대비할 수 있도록 했다.
fetch GET 요청은 무조건
Promise<Response>타입을 작성해주자!
또한 그렇게 받아온 data는 미리 타입에 정의해 둔 것처럼 객체 형태이므로 이 객체가 비어있는지 확인하기 위해 Object.key()를 사용한다. 객체의 속성들을 배열로 변환하고, 그 배열의 길이를 확인하는 것이다.
자, 그럼 이제 서버 컴포넌트에서 데이터 달라고 백엔드에 요청을 넣는다. response는 미리 타입을 설정해 둔 companyInfo 객체타입이다.
구조분해할당을 했기 때문에 바로 companyInfo.image 혹은 companyInfo.ceo같은 식으로 데이터에 접근할 수 있다.
예쁘게 뿌려진 데이터 ㅎ