저번 시간에 API 두개를 병렬 호출 글을 써봤다.
이제 남은건 API 1개인데, 산책로 API 호출만 하면 된다.
<산책로/>
서울시 주요 공원현황
http://openAPI.seoul.go.kr:8088/process.env.NEXT_PUBLIC_SEOUL_PARK/json/SearchParkInfoService/1/132/
서울시 주요 공원 현황 API는 데이터가 132개로 제한 되어있어서 GetStaticProps
로 데이터를 받기로 결정했다.
export const getStaticProps = (async () => {
const results = await searchSeoulParkInfo('SearchParkInfoService/1/135/');
const data: I_SearchParkInfoService = results.data;
return { props: { seoulParkInfo: data.SearchParkInfoService.row } };
}) satisfies GetStaticProps<{
seoulParkInfo: I_SeoulParkAPI[];
}>;
const MapPage = ({ seoulParkInfo }: { seoulParkInfo: I_SeoulParkAPI[] }) => { ... }
Build 할 때 정량 데이터(132개)를 받는 것은 좋은 것 같다.
하나의 샘플 데이터를 받아오면
이렇게 객체 데이터가 들어있다.
여기서 고민할 거리가 생기는데, 이전 블로그에서 각 지역구별 데이터 처리를 위한 UI는 tab형식으로 한다고 결정하였다.
따라서 객체배열을 조작하여 중구
, 도봉구
등으로 데이터를 정제해줘야 한다.
여기서, 선택지는 2가지이다.
무엇을 선택하던, 상관없다는 생각이 막연하게 든다. 그러나, 왜 HashMap이 떠올랐는지를 다시 한번 더 생각 해본 결과
데이터를 관리할 때
HashMap
으로 관리 할 수도 있다고 공부했었고, 요번 프로젝트에서는 다양한 것을 사용하고, 경험 하는 것이 나 자신만의 프로젝트의 당위성이기에 익숙한 것보단, 새로운 것을 사용하여 배우고, 학습, 공부하기로 마음을 잡아 , HashMap으로 관리 하기로 하였다.
각 객체 배열을 HashMap으로 바꾸려면 조건이 위의 사진에서 형광펜칠한 것과 같이
P_ZONE
을 기준으로 HashMap으로 변경 하고자 하여 util 함수를 만들어 봤다.
export function formattedGroupByKey<T extends { [key: string | number]: unknown }>(array: T[], key: keyof T) {
return array.reduce((acc, cur) => {
const stringkey = cur[key] as string;// unknown이다.
if (acc.get(stringkey)) {
acc.get(stringkey)?.push(cur);
} else {
acc.set(stringkey, [cur]);
}
return acc;
}, new Map<keyof T, T[]>());
}
formattedGroupByKey
의 Generic
에 내가 정의한 타입을 넣어주면,
2번째 인자값에 첫 번째 인자값의 key
이 자동 추론 되도록 코드를 짰다.
// types/map/seoul-api/api.d.ts
interface I_SeoulParkAPI {
//... 생략,
P_ZONE: string; // 지역
}
// src/pages/map/map.tsx
const MapPage = ({ seoulParkInfo }: { seoulParkInfo: I_SeoulParkAPI[] }) => {
const formattedData = formattedGroupByKey<I_SeoulParkAPI>(seoulParkInfo, 'P_ZONE');
//...생략
이렇게 해줬는데 Error가 발생 하였다.
요지는
string type에 대한 인덱스 시그니쳐는 I_SeoulParkAPI
에 없다는 문구다.
뭐지 ?? 내가 정의한 타입도 { [key:string|number] : unknown}
이 조건에 되는 것 아닌가??
interface I_Constraint {
[key: string]: string | number | boolean
}
type T_TypeAlias = {
str: string
num: number
bool: boolean
}
interface I_SameInterface {
str: string
num: number
bool: boolean
}
type T_IsToBeTrue = T_TypeAlias extends I_Constraint ? true : false // true
type T_ButFalse = I_SameInterface extends I_Constraint ? true : false // false
어떻게 구글링을 해야 할지 몰라서 stack overflow에 Question을 했다.
어제(20240624) 질문을 올리고 난 후
오늘 확인해보니 중복된 질문이라는 알람이 있어서 들어가서 확인 해 보았다.
Type Alias
에 대해서는 암묵적으로 인덱스 시그니처가 추론되지만, 인터페이스에 대해서는 추론 되지 않는 이슈가 있는데 이것은
RyanCavanaugh(Microsoft의 TypeScript 팀 개발 리드)에 따르면 의도된 것이라고 한다.
의도된 것이라는 것에 주목할 수 있다.
다시 돌아와서,
객체 데이터는 가공되지 않은 상태다.
동물병원&동물약국
그리고 산책로
라는 탭에서 동일하게 사용하려면 데이터, 정확히는 key 값을 바꿔줘야 한다.
SubTabs에 들어가는 각 지역구의 이름들이 들어가 있는 상수(객체 배열데이터)가 아래와 같이 정의 되어있다.
/*
* @explain
{
location: 탭에 보일 UI
api_query : 동물병원&동물약국 API에 사용 할 쿼리
}
*/
export const SEOUL_LOCATION: { location: string; api_query: T_LocationType }[] = [
{
location: '중구',
api_query: 'JG',
},
//... 생략
API를 통해서 받아온 서울근교 산책로 데이터를 HashMap 처리한 상태이다.
위의 상수 값들을 이용해서 객체 배열의 데이터를 내가 원하는 식으로 가공해보자.
export function replaceLocationToApiQuery<T extends { [key: string | number]: unknown }>(
seoulParkInfo: Map<keyof T, T[]>,
) {
SEOUL_LOCATION.forEach(({ location, api_query }) => {
const values = seoulParkInfo.get(location);
seoulParkInfo.delete(location);
seoulParkInfo.set(api_query, values as T[]);
});
return seoulParkInfo;
}
replaceLocationToApiQuery
함수를 통해 가공된 데이터를 보면
key 값이 한글
→ 영어
로 처리 되었다.
값들의 차이가 있는 이유는 사용할 수 없는 데이터들이 있기에 제거 해줬었다. 일을 ... 안하네?
이제 key 값의 가공은 끝났고 카카오 맵에서 각 데이터 UI(=마커로 표기)를 보여주려면 데이터를 가공 해야 하는데 또 다시 고민할 거리에 부딛혔다.