Intro
구름에서 알고 지내던 두리안 님이 5월 초쯤 같이 프로젝트를 해보지 않겠냐고 제안을 해주셨다. 홍삼 백엔드 분들과 여러 차례 프로젝트를 진행해봤기 때문에 다른 백엔드 분과 해보는 것도 좋은 경험이라고 생각했고 전부터 두리안 님과는 개그 코드가 잘 맞아(중요함) 감사히 진행하게 되었다. 그러나 내가 몸서리 치던 지도 API를 사용하는 프로젝트(결과적으론 아님)라서 혼자 커버하기엔 자신이 없었고, 당시 1월부터 솜 님과 프론트엔드 스터디를 진행하고 있었기 때문에 솜 님에게 많이 배울 수 있는 기회라고 생각해 솜 님도 합류하게 되었다.
이미 두리안 님이 어느 정도 각을 잡아 두신 프로젝트라 기획이나 Figma를 손 볼 필요는 없었고, 프론트엔드 역할에 충실하게 데이터 받고 화면을 그리는 일이 주된 업무였다. 이 프로젝트는 [위치에서 가까운 한국의 음식점을 보여주는, 외국인을 위한 로컬 맛집 모음집]이라고 요약할 수 있을 것 같다.
따라서 내가 맡은 업무는
- [현재 위경도 조회하기]
- [현재 위경도를 역지오코딩 해 주소지로 받아오기]
- [솜 님이 보내주신 위경도를 역지오코딩해 현재 위치로 설정하기 / 기준으로 데이터 받아오기]
- [현재 위치를 기준으로 데이터를 무한 스크롤(10개) 받아오기]
이렇게 4가지로 요약할 수 있겠다.
분량 조절 실패로 무한 스크롤 및 UI 구현은 다음 편에서 정리하겠다.
현재 위경도 조회하기
현재 위경도는 HTML5부터 제공하되는 Geolocation API를 사용해 얻을 수 있다.
단 이 API는 유저가 위치 정보에 동의해야만 진행될 수 있다. 우리 서비스의 경우 미동의 한다면 서비스 자체가 이뤄지지 않을 수 있다. 이 부분에 대한 액션은 따로 생각해보지 않았는데 글을 쓰다 보니 지금 생각이 나서(🤦🏻) 고민을 조금 해봐야겠다.
const getPosition = (): Promise<GeolocationPosition> => {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
};
getPosition은 Promise<GeolocationPosition> 타입의 값을 반환한다.
GeolocationPosition - Web API | MDN
GeolocationPosition 인터페이스는 주어진 시간에 장치가 위치한 지점을 나타냅니다. 지점은 Coordinates 객체로 표현하여, 지구를 나타내는 회전타원체 위의 2D 위치와 더불어 높이와 속도 정보를 담습
developer.mozilla.org
MDN에 잘 나와 있다.
특히 내가 사용한 getCurrentPosition은 장치의 현재 위치를 조사한 뒤 GeolocationPosition 객체로 반환한다.
만약 장치의 위치가 바뀔 때마다 등록된 함수를 호출시키려면 watchPosition을 사용해야 한다. clearWatch라는 메서드로 watchPosition에 등록한 특정 콜백을 삭제할 수도 있다고 한다.
결과적으로 저 코드는 Promise를 사용해 비동기적으로 유저의 위치를 가져온다.
성공 시 위치 정보를 resolve 함수에 전달하고, 실패하면 오류를 reject 함수에 전달하는 그런 구조다.
성공 시 받아오는 값을 콘솔에 찍어보면 이렇게 나온다.

여기에서 coords.latitude, coord.longitude가 내가 찾는 유저의 위도와 경도가 되겠다.
현재 위경도를 역지오코딩 해 주소지로 받아오기
그런데 우리가 의도한 것은 유저의 위도와 경도를 표시하는 게 아니라 유저의 위치를 표시하는 것이다.

이렇게 주소지로 나타내기 위해서는 역지오코딩이 필요하다.
역지오코딩이란 지오코딩(주소를 좌표로 변환)의 반대 개념으로, 좌표로 주소를 나타내는 과정을 말한다.
이를 위해서 두리안 님이 구글 맵 API Key를 발급 받아 놓으셔서 구글 맵 API를 사용하기로 했다.
데이터 값을 프론트에서 가공해서 사용하는데 이 부분에 대해서 어떻게 개선할지 논의가 필요하다.
데브옵스의 소견으로는 백엔드를 거치는 게 API의 호출 제한(정확히 용어를 모르겠다)도 막을 수 있다고 하고, 딱 오늘 이야기 했는데 key가 노출되는 바람직하지 않은 상황이기 때문에 아마 빠른 시일 내에 수정이 들어갈 것 같다.
const fetchAddress = async (
latitude: number,
longitude: number
): Promise<string> => {
const apiKey = import.meta.env.VITE_Google_API_KEY;
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${apiKey}&language=en`
);
const data = await response.json();
if (data.status === 'OK') {
const addressData: string = data.results[4].formatted_address;
const commaIndex = addressData.indexOf(',');
const secondCommaIndex =
addressData.indexOf(',', commaIndex + 1) ||
addressData.indexOf(',', commaIndex + 2);
const addressResult = addressData.substring(0, secondCommaIndex);
return addressResult;
} else {
throw new Error('주소를 가져오는 데 문제가 발생했습니다.');
}
};
이 함수는 역지오코딩을 하는 함수다. 즉 위도, 경도(number)를 받고 비동기적으로 주소지(string)을 반환해야 한다.
구글 맵 API에 나와 있는 대로 fetch를 보내고 response를 json으로 바꾸어 사용한다.

성공적으로 데이터를 받아온 경우 이렇게 data가 들어온다.
여기서 좀 골머리를 앓았던 게 0부터 8까지 주소지 표기법이 다 제각각이라는 것이다.
OO구 OO동까지 표시하게 하려면 3번 데이터를 쓰면 되려나 하면 다른 위치에서는 OO도 이런 식으로 파싱이 경우에 따라 다르다. 🤦🏻 아직까지는 어차저차 맞춰놨는데 그 과정이 저 indexOf와 substring이다. 코테에서 가끔 썼던 메소드를 웹 개발에서 쓰게 될 줄 몰랐다. 이런 식으로 case에 따라 파싱하는 게 뭔가 바람직하지 않은 것 같다고 생각되지만 당장 뾰족한 수는 없어서 일단 이렇게 두었다. (좋은 수가 있다면 피드백 부탁드립니다 🥲)
그래서 결론적으로 파싱을 끝내면 한 줄의 addressResult가 나오는데 이것이 바로 역지오코딩의 산물이 되겠다.
만약 data.status가 성공이 아니라면 에러를 던져주도록 if문을 추가해줬다.
다른 페이지에서 보낸 위경도를 역지오코딩해 현재 위치로 설정하기
Change 버튼을 누르면 솜 님이 작업하신 /location-search로 넘어가게 된다.
여기서는 유저가 현재 위치로 설정하고 싶은 주소를 검색할 수 있다.

예를 들어 처음 사이트에 접속했을 때 내 현재 위치가 광교이기 때문에 광교로 나왔는데, Change 버튼을 눌러 '홍대 입구'로 검색하면 홍대 입구를 내 현재 위치로 설정해주는 그런 것이다.
const onPlaceChanged = (autocomplete: google.maps.places.Autocomplete) => {
const place = autocomplete.getPlace();
navigate("/", {
state: {
location: place.geometry?.location?.toJSON(),
},
});
};
이런 식으로 자동 완성이 되는데 저 자동완성 검색어를 클릭하면 navigate를 사용해 현재 위치의 위경도를 객체로 보내준다.

navigate로 페이지 이동만 할 줄 알았지 state를 사용해 객체를 전송할 수 있는 것은 이번에 처음 알았다!
아무튼 이렇게 lat, lng이 메인에 오게 되면, 메인에서는 이 부분을 반영해 다시 역지오코딩을 하게 된다.
// 주소 정보를 가져오는 함수
const getAddressData = async (
changedLat?: number,
changedLng?: number
): Promise<{
address: string;
latitude: number;
longitude: number;
}> => {
let latitude: number;
let longitude: number;
if (changedLat && changedLng) {
latitude = changedLat;
longitude = changedLng;
} else {
// 변경된 위도와 경도가 없는 경우 현재 위치를 가져옴
const position = await getPosition();
latitude = position.coords.latitude;
longitude = position.coords.longitude;
}
// 위도와 경도를 사용하여 주소를 가져옴
const address = await fetchAddress(latitude, longitude);
return { address, latitude, longitude };
};
처음 접속할 때 얻을 수 있는 고유한 위경도를 latitude, longitude라고 할 때 방금처럼 위치를 바꾼 위경도를 changedLat, changedLng이라고 하자.
1) 처음 접속할 때 얻는 고유한 위경도
이것은 파라미터로 전달할 필요 없이 위에서 사용했던 getPosition 함수를 통해 GeolocationPosition 객체에서 받아올 수 있다.
그렇기 때문에 바로 getPosition을 실행 시켜 받은 값을 position.coords로 접근해 얻을 수 있다.
2) 위치를 바꾼 위경도
이는 파라미터로 들어올 수도 있고 들어오지 않을 수도 있기 때문에 ? 연산자를 붙여준다.
만약 위치를 바꾼 위경도가 있다면 이를 그대로 fetchAddress에 보내준다.
이렇게 고유한 위경도 / 위치를 바꾼 위경도에 따라 역지오코딩하는 로직을 나누어 적었다.
이 부분에서 에러가 정말 많이 났던 것 같다... (여기서부터 시작이었지 😇)
JSX로 표현하는 부분인데 TanStack Query를 사용해봤다.
let content;
let latitude: number = 0;
let longitude: number = 0;
const location = useLocation();
const changedLatitude = location?.state?.location?.lat;
const changedLongitude = location?.state?.location?.lng;
const {
data: addressData,
isLoading: isAddressLoading,
isError: isAddressError,
isFetching: isAddressFetching,
error: addressError,
} = useQuery({
queryKey: ['address', location.state],
queryFn: () => getAddressData(changedLatitude, changedLongitude),
});
근데 아직도 isLoading, isFetching이 헷갈린다.
isLoading | isFetching | |
초기 로딩 | true | true |
리패칭 | false | true |
캐싱 | 데이터에 캐시가 없을 때 true | 캐시와 관계 없이 요청 시 true |
주로 쓰임 | 초기 로딩, 첫 번째 요청 | 지속적 업데이트 상태 표시, 리패칭 상태 표시 |
이렇게 인지하고 있는데 그럼 isFetching이 더 큰 개념 아닌가?
isFetching만 사용해도 되는 건가...?
if (isAddressLoading || isAddressFetching) {
content = <div>Loading...</div>;
}
if (isAddressError) {
content = <div>{addressError.message}</div>;
}
if (addressData) {
content = <div>{addressData.address.data.formattedAddress}</div>;
latitude = addressData.latitude;
longitude = addressData.longitude;
localStorage.setItem('latitude', latitude.toString());
localStorage.setItem('longitude', longitude.toString());
}
그래서 content를 구성하는 분기를 isLoading || isFetching일 때 Loading이 나오게 했다. 이렇게 || 연산자로 사용해도 되는지는 잘 모르겠다. 에러가 나면 에러 메세지를 보여주고 정상적으로 데이터가 들어오면 주소를 반환하고, 이 위도 경도를 localStorage에 저장하도록 했다.
저장한 이유는 특정 장소를 눌렀을 때 그 장소를 더 디테일하게 보여주는 /{placeId} 부분에서 api가 위도와 경도를 필요로 하기 때문이다. redux를 써보려고 이걸 전역 상태로 관리했는데 새로고침하면 날라가는 이슈 때문에 어차피 redux-persist든 뭐든 localStorage는 써야했다. 그리고 redux를 사용해보려고 했지만...... 아직 원리는 이해했는데 지금 적용하기는 어려운 정도로 이해한 것 같다; 다시 공부가 필요한 부분임을 느꼈다.
'❔ TypeScript' 카테고리의 다른 글
[TypeScript] TanStack Query 사용 시 Type '{}' is not assignable to type 'ReactNode'. 에러 해결 (0) | 2024.05.12 |
---|---|
[TypeScript] axios error 객체 처리하기 (0) | 2024.04.29 |
[TypeScript] Object is possibly 'undefined' 에러 해결 (0) | 2024.03.21 |
[TypeScript] yarn + Vite + TS로 웹 개발 시작하기 (5) | 2024.03.07 |
Intro
구름에서 알고 지내던 두리안 님이 5월 초쯤 같이 프로젝트를 해보지 않겠냐고 제안을 해주셨다. 홍삼 백엔드 분들과 여러 차례 프로젝트를 진행해봤기 때문에 다른 백엔드 분과 해보는 것도 좋은 경험이라고 생각했고 전부터 두리안 님과는 개그 코드가 잘 맞아(중요함) 감사히 진행하게 되었다. 그러나 내가 몸서리 치던 지도 API를 사용하는 프로젝트(결과적으론 아님)라서 혼자 커버하기엔 자신이 없었고, 당시 1월부터 솜 님과 프론트엔드 스터디를 진행하고 있었기 때문에 솜 님에게 많이 배울 수 있는 기회라고 생각해 솜 님도 합류하게 되었다.
이미 두리안 님이 어느 정도 각을 잡아 두신 프로젝트라 기획이나 Figma를 손 볼 필요는 없었고, 프론트엔드 역할에 충실하게 데이터 받고 화면을 그리는 일이 주된 업무였다. 이 프로젝트는 [위치에서 가까운 한국의 음식점을 보여주는, 외국인을 위한 로컬 맛집 모음집]이라고 요약할 수 있을 것 같다.
따라서 내가 맡은 업무는
- [현재 위경도 조회하기]
- [현재 위경도를 역지오코딩 해 주소지로 받아오기]
- [솜 님이 보내주신 위경도를 역지오코딩해 현재 위치로 설정하기 / 기준으로 데이터 받아오기]
- [현재 위치를 기준으로 데이터를 무한 스크롤(10개) 받아오기]
이렇게 4가지로 요약할 수 있겠다.
분량 조절 실패로 무한 스크롤 및 UI 구현은 다음 편에서 정리하겠다.
현재 위경도 조회하기
현재 위경도는 HTML5부터 제공하되는 Geolocation API를 사용해 얻을 수 있다.
단 이 API는 유저가 위치 정보에 동의해야만 진행될 수 있다. 우리 서비스의 경우 미동의 한다면 서비스 자체가 이뤄지지 않을 수 있다. 이 부분에 대한 액션은 따로 생각해보지 않았는데 글을 쓰다 보니 지금 생각이 나서(🤦🏻) 고민을 조금 해봐야겠다.
const getPosition = (): Promise<GeolocationPosition> => {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
};
getPosition은 Promise<GeolocationPosition> 타입의 값을 반환한다.
GeolocationPosition - Web API | MDN
GeolocationPosition 인터페이스는 주어진 시간에 장치가 위치한 지점을 나타냅니다. 지점은 Coordinates 객체로 표현하여, 지구를 나타내는 회전타원체 위의 2D 위치와 더불어 높이와 속도 정보를 담습
developer.mozilla.org
MDN에 잘 나와 있다.
특히 내가 사용한 getCurrentPosition은 장치의 현재 위치를 조사한 뒤 GeolocationPosition 객체로 반환한다.
만약 장치의 위치가 바뀔 때마다 등록된 함수를 호출시키려면 watchPosition을 사용해야 한다. clearWatch라는 메서드로 watchPosition에 등록한 특정 콜백을 삭제할 수도 있다고 한다.
결과적으로 저 코드는 Promise를 사용해 비동기적으로 유저의 위치를 가져온다.
성공 시 위치 정보를 resolve 함수에 전달하고, 실패하면 오류를 reject 함수에 전달하는 그런 구조다.
성공 시 받아오는 값을 콘솔에 찍어보면 이렇게 나온다.

여기에서 coords.latitude, coord.longitude가 내가 찾는 유저의 위도와 경도가 되겠다.
현재 위경도를 역지오코딩 해 주소지로 받아오기
그런데 우리가 의도한 것은 유저의 위도와 경도를 표시하는 게 아니라 유저의 위치를 표시하는 것이다.

이렇게 주소지로 나타내기 위해서는 역지오코딩이 필요하다.
역지오코딩이란 지오코딩(주소를 좌표로 변환)의 반대 개념으로, 좌표로 주소를 나타내는 과정을 말한다.
이를 위해서 두리안 님이 구글 맵 API Key를 발급 받아 놓으셔서 구글 맵 API를 사용하기로 했다.
데이터 값을 프론트에서 가공해서 사용하는데 이 부분에 대해서 어떻게 개선할지 논의가 필요하다.
데브옵스의 소견으로는 백엔드를 거치는 게 API의 호출 제한(정확히 용어를 모르겠다)도 막을 수 있다고 하고, 딱 오늘 이야기 했는데 key가 노출되는 바람직하지 않은 상황이기 때문에 아마 빠른 시일 내에 수정이 들어갈 것 같다.
const fetchAddress = async (
latitude: number,
longitude: number
): Promise<string> => {
const apiKey = import.meta.env.VITE_Google_API_KEY;
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${apiKey}&language=en`
);
const data = await response.json();
if (data.status === 'OK') {
const addressData: string = data.results[4].formatted_address;
const commaIndex = addressData.indexOf(',');
const secondCommaIndex =
addressData.indexOf(',', commaIndex + 1) ||
addressData.indexOf(',', commaIndex + 2);
const addressResult = addressData.substring(0, secondCommaIndex);
return addressResult;
} else {
throw new Error('주소를 가져오는 데 문제가 발생했습니다.');
}
};
이 함수는 역지오코딩을 하는 함수다. 즉 위도, 경도(number)를 받고 비동기적으로 주소지(string)을 반환해야 한다.
구글 맵 API에 나와 있는 대로 fetch를 보내고 response를 json으로 바꾸어 사용한다.

성공적으로 데이터를 받아온 경우 이렇게 data가 들어온다.
여기서 좀 골머리를 앓았던 게 0부터 8까지 주소지 표기법이 다 제각각이라는 것이다.
OO구 OO동까지 표시하게 하려면 3번 데이터를 쓰면 되려나 하면 다른 위치에서는 OO도 이런 식으로 파싱이 경우에 따라 다르다. 🤦🏻 아직까지는 어차저차 맞춰놨는데 그 과정이 저 indexOf와 substring이다. 코테에서 가끔 썼던 메소드를 웹 개발에서 쓰게 될 줄 몰랐다. 이런 식으로 case에 따라 파싱하는 게 뭔가 바람직하지 않은 것 같다고 생각되지만 당장 뾰족한 수는 없어서 일단 이렇게 두었다. (좋은 수가 있다면 피드백 부탁드립니다 🥲)
그래서 결론적으로 파싱을 끝내면 한 줄의 addressResult가 나오는데 이것이 바로 역지오코딩의 산물이 되겠다.
만약 data.status가 성공이 아니라면 에러를 던져주도록 if문을 추가해줬다.
다른 페이지에서 보낸 위경도를 역지오코딩해 현재 위치로 설정하기
Change 버튼을 누르면 솜 님이 작업하신 /location-search로 넘어가게 된다.
여기서는 유저가 현재 위치로 설정하고 싶은 주소를 검색할 수 있다.

예를 들어 처음 사이트에 접속했을 때 내 현재 위치가 광교이기 때문에 광교로 나왔는데, Change 버튼을 눌러 '홍대 입구'로 검색하면 홍대 입구를 내 현재 위치로 설정해주는 그런 것이다.
const onPlaceChanged = (autocomplete: google.maps.places.Autocomplete) => {
const place = autocomplete.getPlace();
navigate("/", {
state: {
location: place.geometry?.location?.toJSON(),
},
});
};
이런 식으로 자동 완성이 되는데 저 자동완성 검색어를 클릭하면 navigate를 사용해 현재 위치의 위경도를 객체로 보내준다.

navigate로 페이지 이동만 할 줄 알았지 state를 사용해 객체를 전송할 수 있는 것은 이번에 처음 알았다!
아무튼 이렇게 lat, lng이 메인에 오게 되면, 메인에서는 이 부분을 반영해 다시 역지오코딩을 하게 된다.
// 주소 정보를 가져오는 함수
const getAddressData = async (
changedLat?: number,
changedLng?: number
): Promise<{
address: string;
latitude: number;
longitude: number;
}> => {
let latitude: number;
let longitude: number;
if (changedLat && changedLng) {
latitude = changedLat;
longitude = changedLng;
} else {
// 변경된 위도와 경도가 없는 경우 현재 위치를 가져옴
const position = await getPosition();
latitude = position.coords.latitude;
longitude = position.coords.longitude;
}
// 위도와 경도를 사용하여 주소를 가져옴
const address = await fetchAddress(latitude, longitude);
return { address, latitude, longitude };
};
처음 접속할 때 얻을 수 있는 고유한 위경도를 latitude, longitude라고 할 때 방금처럼 위치를 바꾼 위경도를 changedLat, changedLng이라고 하자.
1) 처음 접속할 때 얻는 고유한 위경도
이것은 파라미터로 전달할 필요 없이 위에서 사용했던 getPosition 함수를 통해 GeolocationPosition 객체에서 받아올 수 있다.
그렇기 때문에 바로 getPosition을 실행 시켜 받은 값을 position.coords로 접근해 얻을 수 있다.
2) 위치를 바꾼 위경도
이는 파라미터로 들어올 수도 있고 들어오지 않을 수도 있기 때문에 ? 연산자를 붙여준다.
만약 위치를 바꾼 위경도가 있다면 이를 그대로 fetchAddress에 보내준다.
이렇게 고유한 위경도 / 위치를 바꾼 위경도에 따라 역지오코딩하는 로직을 나누어 적었다.
이 부분에서 에러가 정말 많이 났던 것 같다... (여기서부터 시작이었지 😇)
JSX로 표현하는 부분인데 TanStack Query를 사용해봤다.
let content;
let latitude: number = 0;
let longitude: number = 0;
const location = useLocation();
const changedLatitude = location?.state?.location?.lat;
const changedLongitude = location?.state?.location?.lng;
const {
data: addressData,
isLoading: isAddressLoading,
isError: isAddressError,
isFetching: isAddressFetching,
error: addressError,
} = useQuery({
queryKey: ['address', location.state],
queryFn: () => getAddressData(changedLatitude, changedLongitude),
});
근데 아직도 isLoading, isFetching이 헷갈린다.
isLoading | isFetching | |
초기 로딩 | true | true |
리패칭 | false | true |
캐싱 | 데이터에 캐시가 없을 때 true | 캐시와 관계 없이 요청 시 true |
주로 쓰임 | 초기 로딩, 첫 번째 요청 | 지속적 업데이트 상태 표시, 리패칭 상태 표시 |
이렇게 인지하고 있는데 그럼 isFetching이 더 큰 개념 아닌가?
isFetching만 사용해도 되는 건가...?
if (isAddressLoading || isAddressFetching) {
content = <div>Loading...</div>;
}
if (isAddressError) {
content = <div>{addressError.message}</div>;
}
if (addressData) {
content = <div>{addressData.address.data.formattedAddress}</div>;
latitude = addressData.latitude;
longitude = addressData.longitude;
localStorage.setItem('latitude', latitude.toString());
localStorage.setItem('longitude', longitude.toString());
}
그래서 content를 구성하는 분기를 isLoading || isFetching일 때 Loading이 나오게 했다. 이렇게 || 연산자로 사용해도 되는지는 잘 모르겠다. 에러가 나면 에러 메세지를 보여주고 정상적으로 데이터가 들어오면 주소를 반환하고, 이 위도 경도를 localStorage에 저장하도록 했다.
저장한 이유는 특정 장소를 눌렀을 때 그 장소를 더 디테일하게 보여주는 /{placeId} 부분에서 api가 위도와 경도를 필요로 하기 때문이다. redux를 써보려고 이걸 전역 상태로 관리했는데 새로고침하면 날라가는 이슈 때문에 어차피 redux-persist든 뭐든 localStorage는 써야했다. 그리고 redux를 사용해보려고 했지만...... 아직 원리는 이해했는데 지금 적용하기는 어려운 정도로 이해한 것 같다; 다시 공부가 필요한 부분임을 느꼈다.
'❔ TypeScript' 카테고리의 다른 글
[TypeScript] TanStack Query 사용 시 Type '{}' is not assignable to type 'ReactNode'. 에러 해결 (0) | 2024.05.12 |
---|---|
[TypeScript] axios error 객체 처리하기 (0) | 2024.04.29 |
[TypeScript] Object is possibly 'undefined' 에러 해결 (0) | 2024.03.21 |
[TypeScript] yarn + Vite + TS로 웹 개발 시작하기 (5) | 2024.03.07 |