[박수환] sprint11#144
Hidden character warning
Conversation
kimjong95
left a comment
There was a problem hiding this comment.
typescript를 제대로 활용하고싶다면, typescript에서 타입이 어떻게 추론되는지, 또한 어떠한 방식으로 타입을 지정할수있는지 학습이 필요할 것 같습니다.
typescript를 사용하지만 type시스템을 잘 활용하지 못한다면 오히려 javascript로만 작성할때보다 오버헤드가 발생할 것이고 불편하다고 느낄거에요.
| productId: string; | ||
| } | ||
|
|
||
| interface Comment { |
There was a problem hiding this comment.
model 혹은 viewModel의 형태를 가지고있는 타입 또는 interface는 별도의 파일로분리해서 export하고 원하는 사용처에서 가져가서 사용하면 좋을것 같아요. 아래에서 추가로 볼게요
| isError, | ||
| } = useQuery<Comment[], Error>({ | ||
| queryKey: ["product-comments", productId], | ||
| queryFn: () => axiosProductComments(productId), |
There was a problem hiding this comment.
현재 여기서 받는 response의 타입은 any일것 같습니다
| }; | ||
|
|
||
| //특정 상품의 댓글 가져오기 | ||
| export const axiosProductComments = async (productId: string) => { |
There was a problem hiding this comment.
때문에 여기서 받는 Response의 타입이 Promise<Response> 형태의 타입이여야 하고, 여기서 Comment타입이 사용되어야합니다.
현재는 컴포넌트레벨에서 타입을 정의해주고있는데, 타입추론 관점에서본다면 타입이 시작되는 시점에 타입을 적용해주셔야 해당 값 또는 함수를 사용하는 모든 하위의 코드들에서 타입이 추론될 수 있습니다.
타입스크립트에서는 타입추론을 통해서 모든 곳에 타입을 지정하지 않아도 되는 이유이기도 하고요. 이관점에서본다면 타입을 어디에 지정해주어야할지, 어디서 사용해야할지에 대한 고민이 필요합니다. 이코드를 살짝 수정한다면 다음과같이 수정할 수 있을것 같아요
export type Comment = {
id: string;
content: string;
user: { nickname: string };
createdAt: string;
}
export const axiosProductComments = async (productId: string): Promise<Comment[]> => {
const response = await axiosInstance.get<Comment[]>(`/productComment/${productId}`);
return response.data;
};그렇다면 이 함수의 값을 를 사용하는 곳에서는 모두 타입이 추론되겟죠?!
There was a problem hiding this comment.
그리고 필요하다면 Comment타입을 원하는곳에서 사용할수 있을거에요
| const [page, setPage] = useState(1); | ||
| const [pageSize, setPageSize] = useState(4); | ||
| const [selectedSort, setSelectedSort] = useState("좋아요순"); | ||
| const [searchQuery, setSearchQuery] = useState(""); |
There was a problem hiding this comment.
필요하다면 이곳에도 state들의 타입을 generic을통해서 지정해주면 좋고, 정렬값또한 타입을두고 사용한다면 더 가독성이 좋을것 같아요. 예를 들어볼게요
const SORT_OPTIONS = {
LIKE: "좋아요순",
LATEST: "최신순",
} as const;
// 타입 정의
type SortOptionKey = keyof typeof SORT_OPTIONS;
type SortOptionValue = (typeof SORT_OPTIONS)[SortOptionKey];
type SortApiValue = "like" | "latest";
// 정렬 옵션과 API 값 매핑 객체
const SORT_API_MAP: Record<SortOptionValue, SortApiValue> = {
[SORT_OPTIONS.LIKE]: "like",
[SORT_OPTIONS.LATEST]: "latest",
} as const;
...
const [selectedSort, setSelectedSort] = useState<SortOptionValue>(SORT_OPTIONS.LIKE);
...
const {
data: { products = [], total = 0 } = {},
isLoading,
error,
} = useQuery({
queryKey: ["products", searchQuery, selectedSort, page, pageSize],
queryFn: () =>
axiosProduct(
searchQuery,
SORT_API_MAP[selectedSort],
page,
pageSize
),
});예시에서는 조금 오버한 경향이 있지만, 사용하시는것처럼 key-value형태의 값과 타입이 필요하고 그 관리포인트가 늘어갈때 유용한 방법이기도 합니다.
| 상품 태그 | ||
| </div> | ||
| <div className="flex flex-wrap gap-2 mt-2"> | ||
| {product?.tags?.map((tag, index) => ( |
There was a problem hiding this comment.
- 위에서 product의 타입이 optional이 아니기때문에 해당 코드에서도 optional이 필요없을것 같아요.
- 마찬가지로 tags도 optional이 아니기때문에 필요없을것 같고요.
하지만 의도하지않게 product나 tags가 null이나 undefined형태로 들어올 수 있다면 이 컴포넌트의 상위에서 처리가 필요할수도 있을것 같아요.
위에 설명드린것 처럼 타입의 추론은 코드의선언부부터 사용측으로 추론이되기때문에 선언할때 부터 잘못사용하고있는지 확인이 필요합니다.
| selectedValue, | ||
| placeholder, | ||
| onValueChange, | ||
| className = "", |
There was a problem hiding this comment.
DropdownProps의 각 프로퍼티가 optional이고 이에대한 기본값을 지정해주기위해서 처리해주신것 같은데 좋습니다!
요구사항
기본
프론트엔드
멘토에게