기능 개발 3일차. Supabase 에서 받아온 데이터에 대한 TS type을 제대로 설정하는데 많은 시간을 소모하였다.
특히 하나의 테이블 안에서 또 다른 테이블의 데이터를 가져오는 nested table 을 가져오는 경우 기존 supabase에서 자동 생성한 d.ts 파일의 타입 선언이 제대로 먹히지 않아서 고생했다.
export const getAllComments = async (id: string) => {
let { data: comments, error } = await supabase
.from('comments')
.select(
`
*,
users (
nickname, avatar_url
)
`,
)
.eq('review_id', id);
return comments
};
여기서 받아온 comments 에 대해서 type 선언을 해주고 싶은데 comments 테이블의 행을 그대로 가져오는 것이 아니고 user 테이블에서 nickname과 avatar_url정보도 담아오고 있는 상황이다.
위 스크린샷을 보면 더 이해가 쉬운데, 원래 comments 테이블에는 users 라는 이름의 열이 없지만 getAllComments 함수에서 users 정보도 함께 넣어서 받아오고 있다. 그런데 이것 때문에 supabase 에서 제공하는 d.ts 파일의 type을 그대로 사용할 수 없는 상황이 발생한 것이다.
Tables<'comments'>
이렇게 타입 선언을 하려고 하면 어김없이 해당 타입에는 users 가 존재하지 않는다는 에러가 발생한다.
Tables<'comments'>
를 확장하는 interface를 새로 정의하는 것으로 문제를 해결했다.
export interface CommentsWithUser extends Tables<'comments'> {
users: {
avatar_url: string;
nickname: string;
};
}
export const getAllComments = async (id: string) => {
let { data: comments, error } = await supabase
.from('comments')
.select(
`
*,
users (
nickname, avatar_url
)
`,
)
.eq('review_id', id);
return comments as CommentsWithUser[];
};
CommentsWithUser 는 기존에 이미 존재하는 Tables<'comments'> 타입을 확장하여 추가적으로 users 프로퍼티를 가지게 되었다. 또한 users 프로퍼티의 값은 객체이며 해당 객체 안에 들어있는 두 속성의 type 또한 각각 string 으로 지정해 주었다.
이렇게 만든 CommentsWithUser로 마지막 줄처럼 as CommentsWithUser[];
라고 작성하게 되면 리턴되는 comments가 직접 정의한 type 들로 이루어진 배열이 되어서 처음에 의도 했던 type 지정을 할 수 있게 된다.
TypeScript 를 사용하는 것이 개발에 도움이 되려면 type 지정을 최대한 이른 시점에 해 주어야 한다는 것을 느꼈다.
처음부터 제대로 type 정의를 해두고 개발을 진행하면 이후 개발하는 내내 type 안정성과 자동완성 같은 이점을 누릴 수 있지만, 제대로된 type 지정 없이 먼저 다 만들어 두고 그 이후에 type 을 정의하려고 시도하는 것은 TS의 도움도 받을수 없을 뿐더러 이미 해당 data를 사용하는 컴포넌트가 늘어날대로 늘어나서 비엔나 소세지처럼 연속적으로 줄줄이 에러를 발생시키게 되고, 코딩을 하는동안 자동완성 같은 기본적인 이점조차 누릴 수 없게 된다.
아직 개발해야할 부분이 많은데 내일부터라도 꼭 type 지정은 가능한 이른 시점에 할 생각이다.