<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>BBoBBo-Man.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요</description>
        <lastBuildDate>Sun, 07 Apr 2024 03:13:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>BBoBBo-Man.log</title>
            <url>https://velog.velcdn.com/images/bbobbo-man89/profile/1a2a1008-2189-4088-b3af-be77e19ca88e/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. BBoBBo-Man.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/bbobbo-man89" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[나의 프론트엔드 개발 여정: 배움에서 성장까지]]></title>
            <link>https://velog.io/@bbobbo-man89/%EB%82%98%EC%9D%98-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EC%97%AC%EC%A0%95-%EB%B0%B0%EC%9B%80%EC%97%90%EC%84%9C-%EC%84%B1%EC%9E%A5%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@bbobbo-man89/%EB%82%98%EC%9D%98-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EC%97%AC%EC%A0%95-%EB%B0%B0%EC%9B%80%EC%97%90%EC%84%9C-%EC%84%B1%EC%9E%A5%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Sun, 07 Apr 2024 03:13:40 GMT</pubDate>
            <description><![CDATA[<p>나의 프론트엔드 개발 여정: 배움에서 성장까지
설명
여러분이 지난 6개월 동안 프론트엔드 개발자가 되기 위해 경험한 학습 과정, 도전, 성장을 회고하고 작성해주세요. 여러분의 이야기를 솔직하게 작성하면서, 스스로 학습 여정을 돌아볼 수 있는 소중한 기회가 될 거예요.
세부 내용
6개월 간의 후기를 기록하는 데 어려움을 느낀다면, 아래 내용을 포함하여 작성해보세요. : )</p>
<p>소개
프론트엔드 개발자 취업을 준비하고 있습니다. 
늦은 나이에 방황하는 저에게 주변 지인에서 개발자에 도전해보는 것이 어떻겠느냐의 의견으로 시작을 하였고 의외로 하다보니 몰두하고 재미가 있었습니다. 
이후 더 많은 지식과 경험을 쌓고자 교육을 찾던도중 코드잇 스프린트 과정을 만났습니다. </p>
<p>핵심 학습 내용
여러분이 이 과정에서 중점을 둔 기술들(HTML, CSS, JavaScript, React 등)과 이러한 기술을 학습하면서 겪었던 특별한 경험을 소개해주세요. 어떤 방법이 여러분의 학습에 도움이 되었나요?
검색과 공식문서 참고 도서 다른 부가 기능을 활용하여 문제에 대한 해결을 진행하였고 검색과 공식문서를 통한 습득은 다른사람의 코드도 배울수 있는 기회가 되었습니다.
도전과 극복
학습 과정에서 마주친 도전이나 어려움은 무엇이었고, 이를 어떻게 극복했는지 구체적인 사례를 통해 공유해주세요. 이러한 경험이 여러분의 개발 실력에 어떠한 영향을 미쳤나요?
줄곧 혼자 해오던 작업이나 학습방식이 팀단위로 이루어 지는데 대한 초기의 헤맴과 의외로 의견일치와 세부사항 본인의 작업영역에대한 침범에 제한이 있다는것을 알았습니다 </p>
<p>프로젝트 하이라이트</p>
<p>딱히 어려웠던점 특별한 기술에 관한게 많이 부족하긴합니다. 그러나 
생각했던 대로 업무 나눔 받은 부분은 의외로 평범하게 해결을 했던것 같습니다. 물론 그 과정에서 처음 하는 부분 들은 다시 공부를 해야했지만 결과적으로는 원하는 결과물을 낼수 있었습니다.</p>
<p>배운 점과 앞으로의 목표
배움에는 끝이 없구나 아직 시작조차 안한느낌이 있습니다. 겉핥기식의 공부보다 더 파고 들어 뿌리를 단단히 다지고 싶습니다. 앞으로도 발전하여 개발자 취업에 한걸음 다가가겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[면접및기업정보]]></title>
            <link>https://velog.io/@bbobbo-man89/%EB%A9%B4%EC%A0%91%EB%B0%8F%EA%B8%B0%EC%97%85%EC%A0%95%EB%B3%B4</link>
            <guid>https://velog.io/@bbobbo-man89/%EB%A9%B4%EC%A0%91%EB%B0%8F%EA%B8%B0%EC%97%85%EC%A0%95%EB%B3%B4</guid>
            <pubDate>Sun, 07 Apr 2024 03:06:24 GMT</pubDate>
            <description><![CDATA[<p>스프린터분들의 커리어 발전을 돕기 위해 다양한 수료 후 커리어 지원 서비스를 준비했어요.
여러분의 성장과 취업 성공을 진심으로 응원할테니, 능력 있는 개발자로 도약하기 위한 향후 커리어 여정을 함께해주세요.</p>
<p>모의면접
사전에 안내된 공지에 신청해주신 분들에 한해서 기술 및 인성 모의 면접이 진행돼요. 관련해서는 커리어 코치님과 채용연계매니저 님의 안내를 따라서 잘 준비 및 진행해 주세요.</p>
<p>일정: 4월 17일~5월 3일 중 개별 협의된 일정
대상: 사전 신청자에 한함(추가 신청 불가능)
방식:
인성/기술 모의 면접 각 1회씩 진행
모의면접 내 1:1피드백 포함
인성 모의 면접: 외부 현직 채용담당자가 진행(화상)
기술 모의 면접: 외부 현직 개발자가 진행(화상)
수료생 커뮤니티를 통한 커리어 지원
수료생 커뮤니티를 통해 취업 관련 다양한 정보도 확인하고, 커리어 코치님의 서류 첨삭 서비스도 제공받으세요.</p>
<p>일정: 수료 후 6개월 동안
방식:
다양한 규모별, 분야별 기업 정보 공유
링크<a href="https://codeit.notion.site/5744e0670ee84dd1a949ac44e7db638d">링크텍스트</a>
목적: 다양한 스타트업에 대한 이해도 높이기
업데이트 주기: 주 1회 정도
커넥트(스프린터 전용 채용플랫폼)를 통한 채용공고 큐레이션
<a href="https://connect.codeit.kr/">링크</a>
가입 후 관리자의 권한 부여 후 접속 가능
2기 수료일까지 가입 필수, 수료일 이후 일괄로 권한 부여 예정
이전에 코드잇 스프린트 모집 페이지 에 가입한 적이 있다면, 이미 가입 된 계정이라고 뜰거예요. 그때 가입 한 아이디/비밀번호로 로그인하시면 됩니다. 아이디 및 비밀번호가 기억 나지 않으면 운영 QnA에 올려주세요.
커리어 코치에게 6개월 동안 서류 작성, 지원 과정, 면접 준비 등 도움 요청 가능
수료 후 취업현황 조사
취업지원을 위해 수료 후 일정주기로 취업 현황 및 지원 사항 조사 연락을 드릴 예정
위 현황 조사 진행 시 취업률 체크를 위해 고용 보험 미가입 근로 시, 관련 서류를 요청드릴 수 있으니 많은 협조 부탁드립니다.</p>
<p>앞으로 스프린트 수료생 커뮤니티 내 ‘커리어 지원 채널’에서 커리어 지원 관련 안내를 공지해드릴게요. 적극적인 관심과 참여로 함께해요!</p>
<p>다음 레슨에서는 현재 스프린트 수료생 분들이 지원 가능한 코드잇의 포지션을 몇 개 소개해 드릴게요.<br>코드잇 스프린트 수료생 여러분들의 지원을 기다리고 있으며, 함께 성장하고 발전하는 모습을 기대하겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[.스프린트 수료생 커뮤니티 안내
]]></title>
            <link>https://velog.io/@bbobbo-man89/.%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-%EC%88%98%EB%A3%8C%EC%83%9D-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%95%88%EB%82%B4</link>
            <guid>https://velog.io/@bbobbo-man89/.%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-%EC%88%98%EB%A3%8C%EC%83%9D-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%95%88%EB%82%B4</guid>
            <pubDate>Sun, 07 Apr 2024 02:52:33 GMT</pubDate>
            <description><![CDATA[<p>스프린트와 함께 하는 커리어 성장 과정은 수료 이후에도 계속됩니다. 수료생과 현직 개발자들이 함께 참여하는 스프린트 수료생 커뮤니티를 통해 함께 즐겁게 성장하는 경험을 계속 만들어가세요.</p>
<p>스프린트 수료생 커뮤니티는 스프린트를 수료한 스프린터, 스프린트 과정을 함께 만들어가는 현직 개발자(멘토, 주강사, 특강 강사 등)들이 함께 만들어가는 네트워킹 공간입니다. 디스코드 채널을 통해 상시로 상호작용하며, 다양한 모임과 이벤트가 주기적으로 진행됩니다.</p>
<p>커뮤니티에서 무엇을 할 수 있나요?
다양한 기획 모임 지원
트레바리 같이 &#39;클럽&#39;을 기획하고, 만들고, 운영하는 걸 지원해요. 기술 서적을 함께 모여서 읽을 수도 있고, 사이드 프로젝트를 같이 하는 것도 좋아요. 동아리를 만들어서 취미 활동을 같이 할 수도 있고, 취업 스터디를 할 수도 있어요. 함께 개발 분야에 몸담고 있는 사람과 모이고 싶은 니즈가 있는 사람이라면 누구라도 스프린트 수료생 커뮤니티에서 클럽을 만들고, 참여할 수 있어요(스프린트 수료생 커뮤니티에 참여한 사람들의 혜택이고, 별도 비용은 없습니다).</p>
<p>하나의 클럽당 3개월 동안 활동해야 하며, 최소 월 1회 이상 모임(오프라인/온라인 모두 가능)이 필요합니다. 클럽당 모집 인원은 6~12명이며, 클럽장(클럽을 주도하는 사람)에게는 스프린트에서 소정의 운영 지원금이 제공됩니다. 또한 대면 활동 공간 필요시 사전 논의 후 위워크 일부 공간을 지원해 드릴 수 있습니다.</p>
<p>특별히, 운영진과 함께하는 &#39;클럽&#39;을 만들어서 운영하고 싶은 클럽장 분들은 클럽장 신청 설문을 작성해 주세요. 설문 제출 후 운영진과의 소통이 시작됩니다. 검토 후 커뮤니티 내에서 필수적으로 모집 절차를 거치셔야 하며, 인원 모집 후 채널이 개설됩니다. 클럽 활동은 개설된 채널에서 진행하셔야 하니 이 점 유의해 주시길 바랍니다.</p>
<p>현재 북클럽, 회고 클럽, 취업 스터디, 기술 면접 스터디, 사진 동호회 등 9개의 다양한 클럽들이 활동하고 있어요. 스프린트 커뮤니티의 구성원들과 함께 건강하고 즐거운 클럽 문화를 만들어보아요.</p>
<p>sprint 섬네일</p>
<p>지속적인 정보 공유와 네트워킹
기술 면접 경험 공유, 서류 피드백, 회사 내 소식 등 취업 준비 과정에서 필요한 다양한 정보를 공유해요. 실제 현업에 가더라도 업무적인 고민, 이직에 대한 고민, 커리어적인 궁금증과 지속적인 개발 역량 성장을 위해 필요한 다양한 정보를 서로 주고받을 수 있어요.</p>
<p>또, &#39;클럽&#39;이 아니더라도 누구나 자유롭게 사이드 프로젝트 팀원을 구하거나, 함께 성장할 스터디원을 모집하는 등 다양한 소모임 활동 멤버를 주도적으로 찾을 수도 있어요. 스프린트 수료생 커뮤니티에서 양질의 정보도 잘 얻어 가고, 함께 즐겁게 성장하는 문화도 누려보세요.</p>
<p>커리어 지원 서비스
커리어 코치가 주에 1회씩 모집 중인 채용 공고 및 기업 관련 정보를 정리해서 커뮤니티를 통해 공유할 거예요. 커리어 코치와의 DM을 통해 기업 지원 과정에 대한 조언 요청, 서류 피드백 요청 등도 할 수 있어요. 기업의 채용 담당자 및 현직자와 함께하는 커리어 멘토링 관련 안내도 스프린트 수료생 커뮤니티를 통해 제공될 거예요. 커뮤니티를 통해 안내 및 제공되는 다양한 커리어 서비스도 적극적으로 활용해 보세요.</p>
<p>sprint 섬네일
sprint 섬네일</p>
<p>오프라인/온라인 이벤트
스프린트 과정을 수료한 수료생이라면 스프린트 수료생 커뮤니티에서 진행되는 여러 행사에 참여할 수 있어요. 홈커밍데이, 현직자 특강 등 재밌는 이벤트와 행사들을 주기적으로 진행하려고 하니, 많이 기대해 주시고 참여해 주세요.</p>
<p>스프린트 수료생 커뮤니티 참여 방법
스프린트 수료생 커뮤니티 디스코드 서버 초대 링크는 2기 디스코드 채널에서 별도로 안내해 드릴게요. 안내 잘 참고해서 커뮤니티 입장 및 참여 잘 해주세요.</p>
<p>스프린트 수료생 커뮤니티에 초대되는 시점에, 2기 디스코드 서버에서 out될 예정이에요. 별도로 저장 필요한 사항 있으면 미리 백업해주세요. (정확한 out 시점에 대해서도 추후 안내 예정)</p>
<p>스프린트 수료생 커뮤니티는 여러분의 성공적인 커리어를 위한 의미 있는 서버가 될 거예요. 함께 성장하고 발전하는 추후 여정에도 동참해 주세요!</p>
<p>다음 레슨에서는 수료 후 커리어 지원에 대해 설명드릴게요. 
코드잇 스프린트에서는 수료 후에도 여러분들이 원하시는 꿈을 이룰 수 있도록 다양한 커리어 프로그램을 제공해드리고 있는데요, 이에 대해 다음 레슨에서 더 자세히 설명드리겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[15주차 위클리페이퍼]]></title>
            <link>https://velog.io/@bbobbo-man89/15%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC%ED%8E%98%EC%9D%B4%ED%8D%BC</link>
            <guid>https://velog.io/@bbobbo-man89/15%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC%ED%8E%98%EC%9D%B4%ED%8D%BC</guid>
            <pubDate>Thu, 15 Feb 2024 14:27:30 GMT</pubDate>
            <description><![CDATA[<p>Google 소셜 로그인을 실행하기 위해서는 일련의 과정을 거쳐야 합니다. 여기에는 사용자, 프론트엔드 애플리케이션, 백엔드 서버, 그리고 OpenID Connect 프로바이더 (Google) 간의 상호작용이 포함됩니다. 아래는 각 단계에 대한 요약 설명입니다.</p>
<p>사용자 요청:</p>
<p>사용자가 프론트엔드 애플리케이션에서 &quot;구글 소셜 로그인&quot; 버튼을 클릭합니다.
프론트엔드 요청:</p>
<p>프론트엔드 애플리케이션은 사용자를 구글 로그인 페이지로 리디렉션시키는 요청을 생성합니다.
이 요청은 구글 로그인 API를 호출하는 JavaScript 또는 기타 클라이언트 사이드 코드를 통해 이루어집니다.
사용자 인증:</p>
<p>사용자는 구글 로그인 페이지에서 자신의 계정 정보를 입력합니다.
Google은 사용자의 신원을 확인하고 사용자에게 동의를 요청합니다.
동의 및 권한 부여:</p>
<p>사용자가 동의하고 권한을 부여하면, Google은 사용자의 정보에 접근할 수 있는 권한 부여 코드(authorization code)를 생성합니다.
Authorization Code 수신:</p>
<p>프론트엔드 애플리케이션은 사용자가 권한 부여한 후에 발급된 Authorization Code를 받습니다.
이 코드는 프론트엔드 애플리케이션에 전달됩니다.
백엔드 요청:</p>
<p>프론트엔드 애플리케이션은 Authorization Code와 함께 백엔드 서버에 요청을 보냅니다.
이 요청은 사용자의 인증된 상태를 백엔드 서버로 전달하고, 사용자의 추가 정보에 접근하기 위해 필요한 권한을 요청합니다.
백엔드 인증:</p>
<p>백엔드 서버는 받은 Authorization Code를 사용하여 Google에 사용자의 정보에 대한 액세스 토큰(access token)을 요청합니다.
백엔드 서버는 이러한 요청을 수행하기 위해 백그라운드에서 Google의 OAuth 2.0 인증 서버에 HTTP 요청을 보냅니다.
액세스 토큰 수신:</p>
<p>Google은 백엔드 서버에게 액세스 토큰을 제공합니다.
사용자 정보 요청:</p>
<p>백엔드 서버는 액세스 토큰을 사용하여 Google의 사용자 정보 엔드포인트에 요청을 보냅니다.
사용자 정보 수신:</p>
<p>Google은 백엔드 서버에게 사용자의 정보를 제공합니다.
사용자 응답:</p>
<p>백엔드 서버는 사용자 정보를 받은 후, 프론트엔드 애플리케이션으로 해당 정보를 보냅니다.
프론트엔드 애플리케이션은 이 정보를 가공하여 사용자에게 적절한 응답을 제공합니다.
이러한 과정을 통해 사용자는 구글 소셜 로그인을 통해 애플리케이션에 로그인할 수 있게 됩니다. 이 과정에서 사용자의 정보는 안전하게 전송되고 보호되어야 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MongoDB]]></title>
            <link>https://velog.io/@bbobbo-man89/MongoDB</link>
            <guid>https://velog.io/@bbobbo-man89/MongoDB</guid>
            <pubDate>Tue, 16 Jan 2024 08:35:05 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터베이스-연동하기">데이터베이스 연동하기</h2>
<p>가장 먼저 mongoose.connect() 함수를 사용해서 커넥션을 만들고 사용합니다. 이때 Next.js 환경에서 커넥션을 불필요하게 여러 개 만들 수 있기 때문에, 캐싱 기법을 사용하는데요. 조금은 복잡할 수 있기 때문에 공식 리포지터리에 있는 코드(<a href="https://github.com/vercel/next.js/tree/canary/examples/with-mongodb-mongoose">next.js/examples/with-mongodb-mongoose</a>)를 참고해서 구현하는 걸 권장합니다.</p>
<p>연동이 잘 되었는지 확인하려면 아래와 같이 mongoose.connection.readyState라는 값을 확인할 수 있습니다. 문서에 따르면 접속한 상태에서는 1이라는 값이 출력되어야 합니다. (<a href="https://mongoosejs.com/docs/api/connection.html#Connection.prototype.readyState">Connection.prototype.readyState 문서</a>)</p>
<pre><code>import mongoose from &#39;mongoose&#39;;
// ...
await dbConnect();
console.log(mongoose.connection.readyState);</code></pre><h2 id="모델-만들기">모델 만들기</h2>
<p>mongoose.Schema()를 사용해서 스키마를 생성합니다. 스키마는 모델이 어떤 속성을 가질지 정하는 용도입니다. mongoose.model() 을 사용해서 모델을 생성합니다. 이때 모델의 이름을 첫 번째 아규먼트로 넘겨주는데, 이 이름은 mongoose.models[ ... ]로 참조할 수 있기 때문에 잘 지정했는지 반드시 확인해 주세요.</p>
<p>예를 들어서 ShortLink라는 모델은 아래와 같이 만들 수 있었는데요. 참고로 모듈 파일을 import할 때마다 모델을 생성하는 일이 일어나지 않도록 mongoose.models[&#39;ShortLink&#39;] || mongoose.model(&#39;ShortLink&#39;,shortLinkSchema)처럼 작성해 둔 부분도 눈여겨 봐 주세요.</p>
<pre><code>

import mongoose from &#39;mongoose&#39;;

const shortLinkSchema = new mongoose.Schema(
  {
    title: { type: String, default: &#39;&#39; },
    url: { type: String, default: &#39;&#39; },
    shortUrl: { type: String, default: &#39;&#39; },
  },
  {
    timestamps: true,
  }
);

const ShortLink =
  mongoose.models[&#39;ShortLink&#39;] || mongoose.model(&#39;ShortLink&#39;, shortLinkSchema);

export default ShortLink;</code></pre><h2 id="모델-다루기">모델 다루기</h2>
<h3 id="생성-modelcreate">생성: Model.create()</h3>
<p>아규먼트로 전달한 값으로 도큐먼트를 생성합니다.</p>
<pre><code>

const newShortLink = await ShortLink.create({
  title: &#39;코드잇 커뮤니티&#39;,
  url: &#39;https://www.codeit.kr/community/general&#39;,
});</code></pre><h3 id="여러-개-조회-modelfind">여러 개 조회: Model.find()</h3>
<p>조건에 맞는 모든 도큐먼트를 조회합니다. 이때 조건으로 쓰이는 객체는 MongoDB의 문법을 따릅니다. 간단하게는 속성과 값을 키와 밸류로 하는 객체를 넣어줄 수 있는데요. 혹시 궁금하신 분들은 MongoDB를 공부해 보세요.</p>
<pre><code>

const shortLinks = await ShortLink.find(); // 모든 도큐먼트 조회

const filteredShortLinks = await ShortLink.find({ shortUrl: &#39;c0d317&#39; }) // shortUrl 값이 &#39;c0d317&#39;인 모든 도큐먼트 조회</code></pre><h3 id="아이디로-하나만-조회-modelfindbyid">아이디로 하나만 조회: Model.findById()</h3>
<p>아규먼트로 넘겨준 아이디에 해당하는 도큐먼트를 조회합니다.</p>
<pre><code>const shortLink = await ShortLink.findById(&#39;n3x7j5&#39;);</code></pre><h3 id="아이디로-업데이트하기-modelfindbyidandupdate">아이디로 업데이트하기: Model.findByIdAndUpdate()</h3>
<p>첫 번째 아규먼트로 넘겨준 아이디에 해당하는 도큐먼트를 업데이트합니다. 두 번째 아규먼트로는 업데이트할 값을 넘겨줍니다.</p>
<pre><code>const updatedShortLink = await ShortLink.findByIdAndUpdate(&#39;n3x7j5&#39;, { ... });</code></pre><h3 id="아이디로-삭제하기-modelfindbyidanddelete">아이디로 삭제하기: Model.findByIdAndDelete()</h3>
<p>아규먼트로 넘겨준 아이디에 해당하는 도큐먼트를 삭제합니다.</p>
<pre><code>await ShortLink.findByIdAndDelete(&#39;n3x7j5&#39;);</code></pre><h2 id="그-외에-자주-사용하는-함수-소개">그 외에 자주 사용하는 함수 소개</h2>
<p>아이디 값으로 조회하거나 업데이트하는 것 외에도 조건(MongoDB 문법)으로 사용하는 다양한 함수들이 있습니다. 혹시 더 많은 함수들이 궁금하신 분들은 Mongoose의 <a href="https://mongoosejs.com/docs/api/model.html">Model 문서</a>를 참고해 보세요.</p>
<h3 id="조건으로-하나만-조회">조건으로 하나만 조회</h3>
<p>아규먼트로 조건을 넘겨주고 해당하는 도큐먼트를 하나만 조회합니다.</p>
<pre><code>const shortLink = await ShortLink.findOne({ shortUrl: &#39;c0d317&#39; });</code></pre><h3 id="조건으로-업데이트하기">조건으로 업데이트하기</h3>
<p>첫 번째 아규먼트로 넘겨준 조건에 해당하는 도큐먼트를 업데이트합니다. 두 번째 아규먼트로는 업데이트할 값을 넘겨줍니다.</p>
<pre><code>await ShortLink.updateOne({ _id: &#39;n3x7j5&#39; }, { ... }); // 업데이트만 하고 업데이트 된 값을 리턴하지는 않음</code></pre><pre><code>
const updatedShortLink = await ShortLink.findOneAndUpdate({ _id: &#39;n3x7j5&#39; }, { ... });</code></pre><h3 id="조건으로-삭제하기">조건으로 삭제하기</h3>
<p>아규먼트로 넘겨준 조건에 해당하는 도큐먼트를 삭제합니다.</p>
<pre><code>await ShortLink.deleteOne({ _id: &#39;n3x7j5&#39; }, { ... }); // 삭제만 하고  기존 값을 리턴하지는 않음

const deletedShortLink = await ShortLink.findOneAndDelete({ _id: &#39;n3x7j5&#39; }, { ... });</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js API 라우팅]]></title>
            <link>https://velog.io/@bbobbo-man89/Next.js-API-%EB%9D%BC%EC%9A%B0%ED%8C%85</link>
            <guid>https://velog.io/@bbobbo-man89/Next.js-API-%EB%9D%BC%EC%9A%B0%ED%8C%85</guid>
            <pubDate>Tue, 16 Jan 2024 08:31:19 GMT</pubDate>
            <description><![CDATA[<h2 id="리퀘스트-핸들러-함수">리퀘스트 핸들러 함수</h2>
<p>예를 들어서 /api/short-links로 들어오는 리퀘스트를 처리하려면 /pages/api/short-links.js 또는 /pages/api/short-links/index.js 경로로 파일을 만들고 아래처럼 함수를 default export하면 됩니다.</p>
<pre><code>export default async function handler(req, res) {
  ...
}</code></pre><h2 id="리퀘스트-객체">리퀘스트 객체</h2>
<pre><code>프로퍼티    타입       설명
method      문자열     리퀘스트로 들어온 HTTP 메소드 값
query      객체      쿼리 스트링이나 Next.js에서 사용하는 Params 값이 들어 
                   있는 객체
body      자유로움    리퀘스트의 바디 값
cookie      객체     리퀘스트의 쿠키가 키/밸류로 들어 있는 객체</code></pre><h2 id="리스폰스-객체">리스폰스 객체</h2>
<p>함수 체이닝 방식으로 사용하기 때문에, res.status(201).send()처럼 함수를 이어서 사용할 수 있습니다.</p>
<pre><code>
프로퍼티      타입    설명
status()    함수      리스폰스로 보낼 HTTP 상태 코드를 지정
send()        함수      리스폰스로 보낼 바디를 전달</code></pre><h2 id="참고-자료">참고 자료</h2>
<p>이것 말고도 다양한 프로퍼티와 메소드가 있는데요, 궁금하신 분들은 아래 링크에 있는 공식 문서를 참고해 보세요.</p>
<p><a href="https://nextjs.org/docs/pages/building-your-application/routing/api-routes">API Routes - Request Helpers</a>
<a href="https://nextjs.org/docs/pages/building-your-application/routing/api-routes">API Routes - Response Helpers</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 프리 렌더]]></title>
            <link>https://velog.io/@bbobbo-man89/Next.js-%ED%94%84%EB%A6%AC-%EB%A0%8C%EB%8D%94</link>
            <guid>https://velog.io/@bbobbo-man89/Next.js-%ED%94%84%EB%A6%AC-%EB%A0%8C%EB%8D%94</guid>
            <pubDate>Tue, 16 Jan 2024 04:34:34 GMT</pubDate>
            <description><![CDATA[<h2 id="프리-렌더링pre-rendering">프리 렌더링(Pre-rendering)</h2>
<p>웹 브라우저가 페이지를 로딩하기 이전에 렌더링하는 걸 말합니다. 크게 정적 생성(Static Generation)과 서버사이드 렌더링(Server-side Rendering)으로 나뉩니다. Next.js에서는 기본적으로 모든 페이지를 정적 생성합니다.</p>
<h2 id="정적-생성static-generation">정적 생성(Static Generation)</h2>
<p>프로젝트를 빌드하는 시점에 미리 HTML을 렌더링하는 걸 말합니다. 기본적으로 Next.js에서는 모든 페이지를 정적 생성합니다.</p>
<h2 id="getstaticprops-함수">getStaticProps() 함수</h2>
<p>정적 생성할 때 필요한 데이터를 받아와서 렌더링하고 싶다면getStaticProps() 함수를 구현하고 export하면 됩니다. 객체의 props 프로퍼티로 넘겨줄 Props 객체를 지정하고, 이것을 페이지 컴포넌트에서 사용할 수 있었죠.</p>
<pre><code>
export async function getStaticProps() {
  const res = await axios(&#39;/products/&#39;);
  const products = res.data;

  return {
    props: {
      products,
    },
  };
}

export default function Home({ products }) {
  return (
    &lt;ProductList products={products} /&gt;
  );
}</code></pre><h2 id="getstaticpaths-함수">getStaticPaths() 함수</h2>
<p>/pages/products/[id].js 와 같이 다이나믹 라우팅을 하는 페이지를 정적 생성을 할 때에는 어떤 페이지를 정적 생성할지 지정해줘야 하는데요. getStaticPaths() 라는 함수를 구현하고 export해서 정해줄 수 있었습니다.</p>
<p>getStaticPaths() 함수에서는 리턴 값으로 객체를 리턴하는데, paths 라는 배열에서 각 페이지에 해당하는 정보를 넘겨줄 수 있었습니다. 예를 들어서 id 값이 &#39;1&#39;인 페이지를 정적 생성하려면 { params: { id: &#39;1&#39; } }과 같이 쓸 수 있었습니다.</p>
<p>그리고 fallback 이라는 속성을 사용해서 정적 생성되지 않은 페이지를 처리해 줄 것인지 지정할 수 있었는데요. fallback: true 라고하면 생성되지 않은 페이지로 접속했을 때 getStaticProps() 함수를 실행해 페이지를 만들어서 보여줍니다.</p>
<pre><code>
export async function getStaticPaths() {
  return {
    paths: [
      { params: { id: &#39;1&#39; }},
      { params: { id: &#39;2&#39; }},
    ],
    fallback: true,
  };
}</code></pre><p>getStaticProps() 함수에서는 context 파라미터를 사용해서 필요한 Params(context.params) 값이나 쿼리스트링(context.query) 값을 참조할 수 있었습니다.</p>
<p>그리고 fallback: true라고 지정했다면, 필요한 데이터가 존재하지 않을 수 있기 때문에 적절한 예외처리를 해야 하는데요. { notFound: true } 를 리턴하면 데이터를 찾을 수 없을 때 404 페이지로 이동시킬 수 있습니다.</p>
<pre><code>
export async function getStaticProps(context) {
  const productId = context.params[&#39;id&#39;];

  let product;

  try {
    const res = await axios(`/products/${productId}`);
    product = res.data;
  } catch {
    return {
      notFound: true,
    };
  }

  return {
    props: {
      product,
    },
  };
}
</code></pre><p>만약 fallback: true 를 설정했다면 getStaticProps() 를 실행하는 동안 보여 줄 로딩 페이지를 구현해야 하는데요, 페이지 컴포넌트에서 필요한 데이터가 존재하지 않을 때를 처리해 주면 됩니다.</p>
<pre><code>
export default function Product({ product }) {
  if (!product) {
    return &lt;&gt;로딩 중 ...&lt;/&gt;
  }
  return &lt;&gt;상품 이름: {product.name}&lt;/&gt;;
}</code></pre><h2 id="서버사이드-렌더링server-side-rendering">서버사이드 렌더링(Server-side Rendering)</h2>
<p>Next.js 서버에 리퀘스트가 도착할 때마다 페이지를 렌더링해서 보내주는 방식입니다. getServerSideProps() 함수를 구현하고 export하면 됩니다. 이때 리턴 값으로는 객체를 리턴하는데요. 정적 생성때와 마찬가지로 props 프로퍼티로 Props 객체를 넘겨주면 페이지 컴포넌트에서 받아서 사용할 수 있습니다.</p>
<pre><code>
export async function getServerSideProps() {
  const res = await axios(&#39;/products/&#39;);
  const products = res.data;

  return {
    props: {
      products,
    },
  };
}

export default function Home({ products }) {
  return (
    &lt;ProductList products={products} /&gt;
  );
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 정적생성 SSR]]></title>
            <link>https://velog.io/@bbobbo-man89/Next.js-%EC%A0%95%EC%A0%81%EC%83%9D%EC%84%B1-SSR</link>
            <guid>https://velog.io/@bbobbo-man89/Next.js-%EC%A0%95%EC%A0%81%EC%83%9D%EC%84%B1-SSR</guid>
            <pubDate>Tue, 16 Jan 2024 04:33:18 GMT</pubDate>
            <description><![CDATA[<p>프리 렌더링을 하면 검색 엔진 최적화(SEO)에 도움이 되고, 페이지의 로딩 속도가 빠르다는 장점이 있다고 배웠습니다. 정적 생성과 서버사이드 렌더링 두 가지 선택지가 있었는데요. 이 두 가지를 언제 어떻게 사용하는 것이 좋을까요? 이번 레슨에서는 앞에서 만들었던 페이지들을 다시 살펴보면서 언제 어떤 것을 사용하면 좋을지 알아보도록 하겠습니다.</p>
<p>앞에서 만들었던 페이지</p>
<h3 id="홈페이지">홈페이지</h3>
<p><img src="https://velog.velcdn.com/images/bbobbo-man89/post/252fd039-9aaa-4c41-9673-02e18f1fe776/image.png" alt=""></p>
<p>우선 홈페이지(/pages/index.js)에서는 상품 데이터가 자주 업데이트되지 않는다고 가정했기 때문에, 정적 생성을 했었습니다. getStaticProps() 함수를 구현하고 데이터를 불러와서 정적 생성을 하도록 구현했죠. 만약에 관리자가 상품을 자주 업데이트하거나, 항상 최신의 상품을 보여 줘야 한다면 서버사이드 렌더링을 선택했을 겁니다.</p>
<h3 id="검색-페이지">검색 페이지</h3>
<p><img src="https://velog.velcdn.com/images/bbobbo-man89/post/69c53712-da44-4e01-bab8-9445a3f83414/image.png" alt=""></p>
<p>검색 페이지(/pages/search.js)에서는 주소에 있는 쿼리스트링 값에 따라서 다른 검색 결과를 보여 줘야 하기 때문에, 서버사이드 렌더링을 했었습니다. getServerSideProps() 함수를 구현해서 쿼리스트링에 따라 다른 데이터를 가지고 서버사이드 렌더링을 하도록 구현했죠.</p>
<h3 id="상품-상세-페이지">상품 상세 페이지</h3>
<p><img src="https://velog.velcdn.com/images/bbobbo-man89/post/bd9ba3db-9081-4d32-9ba9-7d4d8f561142/image.png" alt=""></p>
<p>상품 상세 페이지(/pages/items/[id].js)에서는 항상 최신의 리뷰 데이터를 보여주기 위해서, 서버사이드 렌더링을 했었습니다. getServerSideProps() 함수를 구현해서 아이디 값에 따라 다른 데이터를 가지고 서버사이드 렌더링을 하도록 구현했죠. 리퀘스트가 들어올 때마다 매번 리뷰 데이터를 불러와서 렌더링하기 때문에, 항상 최신의 리뷰 데이터로 프리렌더링할 수 있었습니다.</p>
<h3 id="설정-페이지">설정 페이지</h3>
<p><img src="https://velog.velcdn.com/images/bbobbo-man89/post/16c20981-7787-4a52-bc08-a4e85a8fa267/image.png" alt=""></p>
<p>설정 페이지(/pages/settings.js)에서는 딱히 데이터를 사용하지 않았기 때문에, Next.js에서 기본적으로 정적 생성을 하고 있었습니다.</p>
<p>이렇게 페이지마다 데이터를 어떻게 보여줄 것인가에 따라 서버사이드 렌더링, 정적 생성을 다르게 해 줬습니다. Next.js에서는 특별한 경우가 아니라면 되도록이면 정적 생성으로 구현할 것을 권장하고 있는데요. 리퀘스트가 들어올 때마다 매번 렌더링을 하는 것보다 미리 렌더링을 해서 저장해 둔 것을 보내 주는 게 훨씬 빠르기 때문입니다. 그렇다면 언제 서버사이드 렌더링을 고려하는 게 좋을까요?</p>
<h3 id="서버사이드-렌더링을-고려하면-좋은-경우">서버사이드 렌더링을 고려하면 좋은 경우</h3>
<p>이럴 때 서버사이드 렌더링을 고려해 보세요.</p>
<p>항상 최신 데이터를 보여 줘야 하는 경우
데이터가 자주 바뀌는 경우
리퀘스트의 데이터를 사용해야 하는 경우 (예: 헤더, 쿼리스트링, 쿠키 등)
그 외에 특별한 이유가 없다면 되도록 정적 생성을 하는 걸 권장합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[next.js image컴포넌트 head, build 배포]]></title>
            <link>https://velog.io/@bbobbo-man89/next.js-image%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-head-build-%EB%B0%B0%ED%8F%AC</link>
            <guid>https://velog.io/@bbobbo-man89/next.js-image%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-head-build-%EB%B0%B0%ED%8F%AC</guid>
            <pubDate>Tue, 16 Jan 2024 04:30:24 GMT</pubDate>
            <description><![CDATA[<p>이번 레슨에서는  Image 컴포넌트,  Head 컴포넌트, 그리고 빌드와 실행하는 방법에 대해 간단히 정리해보고 넘어가겠습니다.</p>
<h1 id="imag-컴포넌트">Imag 컴포넌트</h1>
<p>Next.js에서는 이미지를 사용할 때 Next.js 서버를 한 번 거쳐서 이미지 최적화를 한 다음 사용할 수 있도록 해 주는데요. 그래서 되도록이면 img 태그보다는 Image 컴포넌트를 사용하는 걸 권장합니다. Image 컴포넌트는 next/image에서 불러와서 사용합니다. 이때 반드시 크기가 있어야 하는데요. width와 height 값을 지정하거나 또는 fill이라는 Prop을 사용할 수 있습니다.</p>
<h3 id="width와-height를-사용하는-경우">width와 height를 사용하는 경우</h3>
<p>img 태그와 마찬가지로 너비와 높이를 지정해 줍니다.</p>
<pre><code>
import Image from &#39;next/image&#39;;

export default function Page() {
  return (
    &lt;&gt;
      &lt;Image
        src=&quot;/images/product.jpeg&quot;
        width={300}
        height={300}
        alt=&quot;상품 이미지&quot;
      /&gt;
    &lt;/&gt;
  );
}</code></pre><h3 id="fill을-사용하는-경우">fill을 사용하는 경우</h3>
<p>이미지 크기를 유연하게 지정해야 할 때는 fill을 사용합니다. 이때 부모 요소에서 position: relative와 같이 포지셔닝해야 하는데요. fill을 사용할 경우 absolute 포지션으로 배치되기 때문에, &quot;가장 가까운 포지셔닝이 된&quot; 조상 요소에 꽉 차도록 이미지가 배치됩니다. 만약 이미지의 비율이 깨지는 것을 막고 싶다면 object-fit: cover 속성으로 이미지를 크롭하시면 됩니다.</p>
<pre><code>
import Image from &#39;next/image&#39;;

export default function Page() {
  return (
    &lt;&gt;
     &lt;div
        style={{
          position: &#39;relative&#39;,
          width: &#39;100%&#39;,
          height: &#39;300px&#39;,
        }}
      &gt;
        &lt;Image
          src=&quot;/images/product.jpeg&quot;
          fill
          alt=&quot;상품 이미지&quot;
          style={{
            objectFit: &#39;cover&#39;,
          }}
        /&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre><h1 id="head-컴포넌트">Head 컴포넌트</h1>
<p>next/head에서 불러와서 Head 컴포넌트 안에 head 태그에 넣고 싶은 코드를 작성하면 됩니다.</p>
<pre><code>
import Head from &#39;next/head&#39;;

export default function Page() {
  return (
    &lt;&gt;
      &lt;Head&gt;
        &lt;title&gt;페이지 제목&lt;/title&gt;
        &lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot; /&gt;
      &lt;/Head&gt;
      ...
    &lt;/&gt;
  );
}</code></pre><p>만약 사이트 전체에 공통으로 적용하고 싶다면 /pages/_app.js 파일에서 Head 컴포넌트를 활용해 보세요.</p>
<pre><code>
pages/_app.js

import Head from &#39;next/head&#39;;

export default function App({ Component, pageProps }) {
  return (
    &lt;&gt;
      &lt;Head&gt;
        &lt;title&gt;사이트 기본 제목&lt;/title&gt;
        &lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot; /&gt;
      &lt;/Head&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/&gt;
  );
}</code></pre><h2 id="개발모드-빌드-실행-그리고-배포">개발모드, 빌드, 실행 그리고 배포</h2>
<h3 id="개발-서버-켜기">개발 서버 켜기</h3>
<p>프로젝트 폴더에서 터미널을 연 다음, 아래 명령을 입력해서 개발 서버를 실행할 수 있습니다. 개발 모드이기 때문에 새로고침 없이도 수정 사항을 그때 그때 확인할 수 있습니다.</p>
<pre><code>npm run dev</code></pre><h3 id="빌드하기">빌드하기</h3>
<p>Next.js 프로젝트를 배포하려면 우선 실행 가능한 형태로 코드를 변환한 다음에, 서버에서 실행을 해야 하는데요. 이때 코드를 변환하는 과정을 &quot;빌드&quot;라고 합니다. 빌드를 하려면 프로젝트 폴더에서 터미널을 연 다음, 아래 명령어를 입력합니다.</p>
<pre><code>npm run build</code></pre><p>그럼 .next 폴더에 실행에 필요한 파일들이 생성됩니다.</p>
<h3 id="실행-하기">실행 하기</h3>
<p>프로젝트를 빌드했다면 이제 실행할 수 있습니다. 마찬가지로 프로젝트 폴더에서 터미널을 연 다음, 아래 명령어를 입력합니다.</p>
<pre><code>npm run start</code></pre><h3 id="배포하기">배포하기</h3>
<p>Vercel(<a href="https://vercel.com/)%EC%9D%B4%EB%9D%BC%EB%8A%94">https://vercel.com/)이라는</a> 서비스를 이용하면 Next.js 프로젝트를 간편하게 배포할 수 있었는데요. GitHub 리포지토리와 연동해 놓으면, 리포지토리가 업데이트될 때마다 빌드와 실행 과정을  Vercel이 알아서 수행합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 구글폰트 적용하기]]></title>
            <link>https://velog.io/@bbobbo-man89/Next.js-%EA%B5%AC%EA%B8%80%ED%8F%B0%ED%8A%B8-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@bbobbo-man89/Next.js-%EA%B5%AC%EA%B8%80%ED%8F%B0%ED%8A%B8-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 16 Jan 2024 04:26:45 GMT</pubDate>
            <description><![CDATA[<p>요즘 구글 폰트를 사용한 사이트를 많이 볼 수 있는데요. 무난한 디자인에 구글에서 적용할 수 있는 코드도 제공하기 때문에 많은 곳에서 활용하고 있죠. Next.js에서는 구글 폰트를 위한 기능도 제공하는데요. 구글 폰트를 편하게 쓰는 것뿐만 아니라 여러 가지 최적화도 함께 제공합니다. 이번 레슨에서는 Next.js에서 구글 폰트를 적용하는 방법에 대해 소개해드리겠습니다.</p>
<p>예를 들어서 Noto Sans KR이라는 폰트를 적용해 볼게요. _app.js 파일에서 적용할 건데요. @next/font/google이라는 패키지에서 Noto_Sans_KR을 임포트하고 아래처럼 객체를 만듭니다.</p>
<pre><code>/pages/_app.js

import { Noto_Sans_KR } from &#39;@next/font/google&#39;;

const notoSansKR = Noto_Sans_KR({
  weight: [&#39;400&#39;, &#39;700&#39;],
  subsets: [],
});</code></pre><p>weight 프로퍼티에는 사용할 폰트 굵기를 적었는데요. 굵기 400, 700을 갖는 폰트를 쓸 겁니다. 여기서 주의하실 점은 숫자(400, 700 같은 형태)가 아니라 문자열(&#39;400&#39;, &#39;700&#39; 같은 형태)라는 겁니다.</p>
<p>subsets는 빈 배열로 했는데요. 서브셋이라는 건 폰트에서 영문, 한글 이런 식으로 사용할 글자들만 골라서 사용할 때 쓰는 건데, 일단 전부 다 사용하는 걸로 했습니다. 만약에 영문만 사용하는 폰트라면 [&#39;latin&#39;]과 같이 써 주면 됩니다.</p>
<p>폰트를 적용하려면 notoSansKR 객체의 className 프로퍼티를 사용할 수 있는데요. 이 클래스가 적용된 요소 안에서는 폰트를 적용하게 됩니다.</p>
<pre><code>&lt;main className={notoSansKR.className}&gt;
  ...
&lt;/main&gt;
아니면 Next.js에서 제공하는 Head 컴포넌트를 활용해서 전역 스타일로 적용할 수도 있습니다.

&lt;Head&gt;
  &lt;style&gt;{`
    html {
      font-family: ${notoSansKR.style.fontFamily}, sans-serif;
    }
  `}&lt;/style&gt;
&lt;/Head&gt;</code></pre><p>Next.js는 어떤 최적화를 하고 있는 걸까요? 폰트를 적용하고 개발자 도구를 열어서 Network 탭의 세부 탭인 Font 탭을 살펴보면 구글 사이트가 아니라, 우리 사이트에서 폰트 파일을 받아 오는 걸 알 수 있습니다. 그래서 초기 로딩 속도가 훨씬 빨라지죠.
<img src="https://velog.velcdn.com/images/bbobbo-man89/post/0c2106bb-6f1a-45d9-b714-1f224662a156/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[13주차 위클리 페이퍼]]></title>
            <link>https://velog.io/@bbobbo-man89/13%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</link>
            <guid>https://velog.io/@bbobbo-man89/13%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</guid>
            <pubDate>Sun, 14 Jan 2024 12:16:08 GMT</pubDate>
            <description><![CDATA[<h1 id="cors-에러에-대해-설명하고-어떻게-해결하면-될지-설명해-주세요">CORS 에러에 대해 설명하고, 어떻게 해결하면 될지 설명해 주세요.</h1>
<h3 id="corscross-origin-resource-sharing-에러에-대한-설명">CORS(Cross-Origin Resource Sharing) 에러에 대한 설명:</h3>
<p>CORS는 웹 브라우저에서 실행되는 스크립트가 다른 도메인의 자원에 접근할 때 발생하는 보안 기능입니다. 웹 브라우저는 보안상의 이유로 동일 출처 정책(Same-Origin Policy)을 따르는데, 이는 다른 도메인에서 리소스를 요청하는 것을 제한합니다. 만약 서로 다른 도메인에서 데이터를 주고받아야 하는데, 서버 측에서 CORS 헤더가 적절히 설정되지 않은 경우, 브라우저는 요청을 차단하고 CORS 에러를 발생시킵니다.</p>
<h3 id="cors-에러가-발생하는-상황">CORS 에러가 발생하는 상황:</h3>
<p>서로 다른 도메인에 위치한 웹 애플리케이션에서 API에 접근하려고 할 때.
XMLHttpRequest 또는 Fetch API를 사용해 다른 도메인의 리소스를 요청할 때.
CORS 에러 해결 방법:</p>
<h3 id="서버-측-cors-헤더-설정">서버 측 CORS 헤더 설정:</h3>
<p>API 서버에서는 요청을 허용할 도메인을 명시하는 CORS 헤더를 응답에 포함시켜야 합니다.</p>
<p>예를 들어, 모든 도메인에서의 요청을 허용하려면 다음과 같이 설정할 수 있습니다:</p>
<pre><code>Access-Control-Allow-Origin: *</code></pre><h3 id="또는-특정-도메인만-허용하려면">또는 특정 도메인만 허용하려면:</h3>
<pre><code>Access-Control-Allow-Origin: http://example.com</code></pre><h3 id="cors-미들웨어-사용">CORS 미들웨어 사용:</h3>
<p>서버 프레임워크나 미들웨어를 사용하여 CORS 정책을 간편하게 설정할 수 있습니다.</p>
<p>Express를 사용하는 경우 cors 미들웨어를 설치하고 적용할 수 있습니다.</p>
<pre><code>npm install cors</code></pre><pre><code>const express = require(&#39;express&#39;);
const cors = require(&#39;cors&#39;);
const app = express();

app.use(cors());</code></pre><h3 id="인증-정보-허용">인증 정보 허용:</h3>
<p>만약 요청이 사용자의 인증 정보를 포함한다면, 서버는 Access-Control-Allow-Credentials 헤더를 true로 설정해야 합니다.</p>
<pre><code>Access-Control-Allow-Credentials: true</code></pre><h3 id="전체-요청-허용-설정">전체 요청 허용 설정:</h3>
<p>서버에서 모든 HTTP 메서드 및 헤더, 요청을 허용하도록 설정하려면 Access-Control-Allow-Methods 및 Access-Control-Allow-Headers 헤더를 사용합니다.</p>
<pre><code>Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization</code></pre><h3 id="preflight-요청-처리">Preflight 요청 처리:</h3>
<p>특정 타입의 요청에 대한 사전 검사(preflight) 요청에 응답하기 위해 서버에서는 OPTIONS 메서드를 허용하도록 설정해야 합니다.</p>
<pre><code>Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, DELETE</code></pre><p>이러한 방법들을 통해 서버 측에서 CORS 정책을 적절히 설정하여 CORS 에러를 해결할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[next.js - 사이트 완성하기 정리]]></title>
            <link>https://velog.io/@bbobbo-man89/next.js-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%99%84%EC%84%B1%ED%95%98%EA%B8%B0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@bbobbo-man89/next.js-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%99%84%EC%84%B1%ED%95%98%EA%B8%B0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 10 Jan 2024 06:46:55 GMT</pubDate>
            <description><![CDATA[<p>이번 레슨에서는  Image 컴포넌트,  Head 컴포넌트, 그리고 빌드와 실행하는 방법에 대해 간단히 정리해보고 넘어가겠습니다.</p>
<h1 id="image-컴포넌트">Image 컴포넌트</h1>
<p>Next.js에서는 이미지를 사용할 때 Next.js 서버를 한 번 거쳐서 이미지 최적화를 한 다음 사용할 수 있도록 해 주는데요. 그래서 되도록이면 img 태그보다는 Image 컴포넌트를 사용하는 걸 권장합니다. Image 컴포넌트는 next/image에서 불러와서 사용합니다. 이때 반드시 크기가 있어야 하는데요. width와 height 값을 지정하거나 또는 fill이라는 Prop을 사용할 수 있습니다.</p>
<h2 id="width와-height를-사용하는-경우">width와 height를 사용하는 경우</h2>
<p>img 태그와 마찬가지로 너비와 높이를 지정해 줍니다.</p>
<pre><code>
import Image from &#39;next/image&#39;;

export default function Page() {
  return (
    &lt;&gt;
      &lt;Image
        src=&quot;/images/product.jpeg&quot;
        width={300}
        height={300}
        alt=&quot;상품 이미지&quot;
      /&gt;
    &lt;/&gt;
  );
}</code></pre><h2 id="fill을-사용하는-경우">fill을 사용하는 경우</h2>
<p>이미지 크기를 유연하게 지정해야 할 때는 fill을 사용합니다. 이때 부모 요소에서 position: relative와 같이 포지셔닝해야 하는데요. fill을 사용할 경우 absolute 포지션으로 배치되기 때문에, &quot;가장 가까운 포지셔닝이 된&quot; 조상 요소에 꽉 차도록 이미지가 배치됩니다. 만약 이미지의 비율이 깨지는 것을 막고 싶다면 object-fit: cover 속성으로 이미지를 크롭하시면 됩니다.</p>
<pre><code>
import Image from &#39;next/image&#39;;

export default function Page() {
  return (
    &lt;&gt;
     &lt;div
        style={{
          position: &#39;relative&#39;,
          width: &#39;100%&#39;,
          height: &#39;300px&#39;,
        }}
      &gt;
        &lt;Image
          src=&quot;/images/product.jpeg&quot;
          fill
          alt=&quot;상품 이미지&quot;
          style={{
            objectFit: &#39;cover&#39;,
          }}
        /&gt;
      &lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre><h1 id="head-컴포넌트">Head 컴포넌트</h1>
<p>next/head에서 불러와서 Head 컴포넌트 안에 head 태그에 넣고 싶은 코드를 작성하면 됩니다.</p>
<pre><code>
import Head from &#39;next/head&#39;;

export default function Page() {
  return (
    &lt;&gt;
      &lt;Head&gt;
        &lt;title&gt;페이지 제목&lt;/title&gt;
        &lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot; /&gt;
      &lt;/Head&gt;
      ...
    &lt;/&gt;
  );
}</code></pre><p>만약 사이트 전체에 공통으로 적용하고 싶다면 /pages/_app.js 파일에서 Head 컴포넌트를 활용해 보세요.</p>
<pre><code>
pages/_app.js

import Head from &#39;next/head&#39;;

export default function App({ Component, pageProps }) {
  return (
    &lt;&gt;
      &lt;Head&gt;
        &lt;title&gt;사이트 기본 제목&lt;/title&gt;
        &lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot; /&gt;
      &lt;/Head&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/&gt;
  );
}</code></pre><h1 id="개발모드-빌드-실행-그리고-배포">개발모드, 빌드, 실행 그리고 배포</h1>
<h2 id="개발-서버-켜기">개발 서버 켜기</h2>
<p>프로젝트 폴더에서 터미널을 연 다음, 아래 명령을 입력해서 개발 서버를 실행할 수 있습니다. 개발 모드이기 때문에 새로고침 없이도 수정 사항을 그때 그때 확인할 수 있습니다.</p>
<pre><code>npm run dev</code></pre><h2 id="빌드하기">빌드하기</h2>
<p>Next.js 프로젝트를 배포하려면 우선 실행 가능한 형태로 코드를 변환한 다음에, 서버에서 실행을 해야 하는데요. 이때 코드를 변환하는 과정을 &quot;빌드&quot;라고 합니다. 빌드를 하려면 프로젝트 폴더에서 터미널을 연 다음, 아래 명령어를 입력합니다.</p>
<pre><code>npm run build</code></pre><p>그럼 .next 폴더에 실행에 필요한 파일들이 생성됩니다.</p>
<h2 id="실행-하기">실행 하기</h2>
<p>프로젝트를 빌드했다면 이제 실행할 수 있습니다. 마찬가지로 프로젝트 폴더에서 터미널을 연 다음, 아래 명령어를 입력합니다.</p>
<pre><code>npm run start</code></pre><h2 id="배포하기">배포하기</h2>
<p>Vercel(<a href="https://vercel.com/">https://vercel.com/</a>)이라는 서비스를 이용하면 Next.js 프로젝트를 간편하게 배포할 수 있었는데요. GitHub 리포지토리와 연동해 놓으면, 리포지토리가 업데이트될 때마다 빌드와 실행 과정을  Vercel이 알아서 수행합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js API 라우팅]]></title>
            <link>https://velog.io/@bbobbo-man89/Next.js-API-%EB%9D%BC%EC%9A%B0</link>
            <guid>https://velog.io/@bbobbo-man89/Next.js-API-%EB%9D%BC%EC%9A%B0</guid>
            <pubDate>Tue, 09 Jan 2024 08:40:02 GMT</pubDate>
            <description><![CDATA[<p>Next.js에서는 페이지를 만드는 것처럼 간단하게 백엔드 API를 만들 수 있는데요. 사실상 작은 Node.js 서버를 구현할 수 있습니다. 백엔드 개발자 없이 간단한 API도 개발하고 싶고, 프론트엔드도 개발하고 싶은 사람들에게 유용한 기능이겠죠? 이번 레슨에서는 간단한 예시를 통해서 어떤 기능인지 살펴보고 넘어가겠습니다.</p>
<p>우선 /pages 폴더 아래에 /api라는 폴더를 만들고요, 여기다가 특별한 형태의 자바스크립트 파일을 추가하면 됩니다.</p>
<h2 id="pagesapicartjs">/pages/api/cart.js</h2>
<pre><code>
let cart = [];

export default function handler(req, res) {
  if (req.method === &#39;GET&#39;) {
    return res.status(200).json(cart);
  } else if (req.method === &#39;PUT&#39;) {
    cart = req.body;
    return res.status(200).json(cart);
  } else {
    return res.sendStatus(404);
  }
}</code></pre><p>이렇게 default export로 리퀘스트 객체(req)와 리스폰스 객체(res)를 파라미터로 받는 함수를 만들면 됩니다. 리퀘스트 객체와 리스폰스 객체는 Node.js의 리퀘스트 객체와 리스폰스 객체인데요.</p>
<p>위 코드는 GET 리퀘스트를 보냈을 때 cart 배열을 리스폰스로 보내 주고, PUT 리퀘스트를 보냈을 때 cart 배열을 수정하는 간단한 코드입니다.</p>
<p>리퀘스트와 리스폰스 객체에 대해서는 이번 토픽에서 자세히 다루지 않겠습니다. 혹시 궁금하신 분들은 코드잇에서 Node.js 관련 토픽을 들어보세요.</p>
<p>이 API의 주소는 Next.js에서 페이지를 만들었을 때의 주소와 마찬가지입니다. /api/cart.js라는 경로이니까 /api/cart라는 주소로 리퀘스트를 보내면 파일에 있는 핸들러 함수를 실행해서 리스폰스를 보내 주는 형태입니다.</p>
<p>웹 브라우저에서<a href="http://localhost:3000/api/cart%EB%9D%BC%EB%8A%94">http://localhost:3000/api/cart라는</a> 주소로 접속하거나, API 테스트를 해 보면 아래와 같은 JSON 데이터가 리스폰스로 전달될 겁니다.</p>
<p>GET 리퀘스트를 보낼 때</p>
<pre><code>GET http://localhost:3000/api/cart
Content-Type: application/json</code></pre><p>GET 리퀘스트를 보내고 받은 리스폰스 예시</p>
<pre><code>[]</code></pre><p>PUT 리퀘스트를 보낼 때</p>
<pre><code>PUT http://localhost:3000/api/cart
Content-Type: application/json

[1, 2, 3]</code></pre><p>PUT 리퀘스트를 보내고 받은 리스폰스 예시</p>
<pre><code>[1, 2, 3]</code></pre><p>리퀘스트 객체를 활용하면 리퀘스트의 헤더나 쿠키 같은 값을 사용해서 다양한 동작을 하도록 만들 수 있는데요. 이번 토픽에선 따로 API를 만들거나 하지는 않을 거니까, 일단 이런 기능이 있다는 정도로만 알고 넘어갑시다. 혹시 더 궁금하신 분들은 아래의 링크를 참고해 보세요.</p>
<p>참고 자료
<a href="https://nextjs.org/docs/pages/building-your-application/routing/api-routes">Next.js - API Routes</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[학원 API]]></title>
            <link>https://velog.io/@bbobbo-man89/%ED%95%99%EC%9B%90-API</link>
            <guid>https://velog.io/@bbobbo-man89/%ED%95%99%EC%9B%90-API</guid>
            <pubDate>Tue, 09 Jan 2024 08:38:23 GMT</pubDate>
            <description><![CDATA[<p>학원API
이제부터 사이트에 API를 연동해 볼 건데요. 아래 두 문서를 참고해서 API를 연동해 보겠습니다. 필요할 때마다 아래 API 문서를 찾아보면서 웹사이트를 구현해 보세요.</p>
<p><a href="https://www.codeit.kr/tutorials/53/codeitmall-api-documentation">Codeitmall API 문서</a>
<a href="https://www.codeit.kr/tutorials/55/watchit-api-documentation">
Watchit API 문서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js - Pages Router타입]]></title>
            <link>https://velog.io/@bbobbo-man89/Next.js-Pages-Router%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@bbobbo-man89/Next.js-Pages-Router%ED%83%80%EC%9E%85</guid>
            <pubDate>Tue, 09 Jan 2024 08:36:37 GMT</pubDate>
            <description><![CDATA[<p>Next.js에서 특별하게 사용하는 타입은 많지 않기 때문에 공식문서만 읽어보아도 충분합니다. 이번 레슨에서는 공식 문서의 내용을 기반으로 타입을 활용하는 방법에 대해서 알아보도록 하겠습니다.</p>
<h2 id="커스텀-app">커스텀 App</h2>
<p>_app.tsx 파일에선 웹사이트 전체에 공통적으로 렌더링 되는 App이라는 컴포넌트를 만들죠? 이 컴포넌트의 Props 형태는 정해져 있는데요. AppProps라는 타입을 next/app 패키지에서 불러와서 아래처럼 사용하면 됩니다.</p>
<pre><code> _app.tsx 

import Head from &#39;next/head&#39;;
import { AppProps } from &#39;next/app&#39;;
import Header from &#39;@/components/Header&#39;;
import &#39;@/styles/global.css&#39;;

export default function App ({ Component, pageProps }: AppProps) {
  return (
    &lt;&gt;
      &lt;Head&gt;
        &lt;title&gt;Codeitmall&lt;/title&gt;
        &lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot; /&gt;
      &lt;/Head&gt;
      &lt;Header /&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/&gt;
  );
}</code></pre><h2 id="프리-렌더링">프리 렌더링</h2>
<p>정적 생성
Next.js에선 빌드 시점에 리액트 코드를 미리 렌더링해 둘 수 있는데요. 이런 걸 정적 생성(Static Generation)이라고 합니다.</p>
<pre><code>import Image from &#39;next/image&#39;;

export async function getStaticPaths () {
  const res = await fetch(&#39;https://learn.codeit.kr/api/codeitmall/products/&#39;);
  const data = await res.json();
  const products = data.results;
  const paths = products.map((product) =&gt; ({
    params: { id: String(product.id) },
  }));

  return {
    paths,
    fallback: true,
  };
};

export async function getStaticProps(context) {
  const productId = context.params [&#39;id&#39;];

  let product;
  try {
    const res = await fetch(`https://learn.codeit.kr/api/codeitmall/products/${productId}`);
    const data = await res.json();
    product = data;
  } catch {
    return {
      notFound: true,
    };
  }

  return {
    props: {
      product,
    },
  };
}

export default function ProductPage({ product }) {
  return (
    &lt;div&gt;
      &lt;h1&gt;{product.name}&lt;/h1&gt;
      &lt;Image
        src={product.imgUrl}
        width=&quot;480&quot;
        height=&quot;480&quot;
        alt={product.name}
      /&gt;
    &lt;/div&gt;
  );
}</code></pre><p>위 예시 코드를 살펴보면, getStaticPaths()라는 함수에선  <a href="https://learn.codeit.kr/api/codeitmall/products/%EB%9D%BC%EB%8A%94">https://learn.codeit.kr/api/codeitmall/products/라는</a> API 주소에 리퀘스트를 보내서  상품 목록 데이터를 받았습니다. 이 데이터로 아이디 값들을 모아서 params 값들을 만들고요. 이 값을 바탕으로 getStaticProps() 함수에서는 context 값을 활용해 리퀘스트를 보내서 상품 데이터를 받아옵니다. 이걸 product라는 이름의 Prop으로 내려주고 있죠.</p>
<p>Next.js에선 기본적으로 화살표 함수로 만든 다음 아래와 같이 GetStaticPaths, GetStaticProps 타입을 지정하는 걸 권장합니다.
<img src="https://velog.velcdn.com/images/bbobbo-man89/post/d77b5cdd-e347-433e-a216-690d250a9932/image.png" alt=""></p>
<p>context 값에 마우스를 호버해 보면 타입이 잘 추론되죠?</p>
<pre><code>import { GetStaticPaths, GetStaticProps } from &#39;next&#39;;
// ...

export const getStaticPaths: GetStaticPaths = async () =&gt; {
  // ...

  return {
    paths,
    fallback: true,
  };
};

export const getStaticProps: GetStaticProps = async (context) =&gt; {
  // ...

  return {
    props: {
      product,
    },
  };
}</code></pre><p>이번엔 페이지의 타입을 정의해 보겠습니다. 우선 일반적인 리액트 컴포넌트의 Props 타입을 정의하듯이 Props를 정의하고요. 이걸 getStaticProps() 함수의 제네릭으로 지정해 줍니다.</p>
<pre><code>interface Props {
  product: Product;
}

export const getStaticProps: GetStaticProps&lt;Props&gt; = async (context) =&gt; {
  // ...
  return {
    props: {
      product,
    },
  };
};

export default function ProductPage({ product }: Props) {
  return (
    &lt;div&gt;
      &lt;h1&gt;{product.name}&lt;/h1&gt;
      &lt;Image
        src={product.imgUrl}
        width=&quot;480&quot;
        height=&quot;480&quot;
        alt={product.name}
      /&gt;
    &lt;/div&gt;
  );
}</code></pre><h2 id="서버사이드-렌더링">서버사이드 렌더링</h2>
<p>Next.js 서버에 리퀘스트가 들어올 때마다 렌더링을 해서 보내주는 서버사이드 렌더링의 경우에도 비슷한 방식으로 해주면 됩니다. 앞에서 보았던 예시에서 서버사이드 렌더링으로 바꾼 코드를 한번 보겠습니다.</p>
<pre><code>
import Image from &#39;next/image&#39;;

export async function getServerSideProps(context) {
  const productId = context.params[&#39;id&#39;];

  let product;
  try {
    const res = await fetch(`https://learn.codeit.kr/api/codeitmall/products/${productId}`);
    const data = await res.json();
    product = data;
  } catch {
    return {
      notFound: true,
    };
  }

  return {
    props: {
      product,
    },
  };
}

export default function ProductPage({ product }) {
  return (
    &lt;div&gt;
      &lt;h1&gt;{product.name}&lt;/h1&gt;
      &lt;Image
        src={product.imgUrl}
        width=&quot;480&quot;
        height=&quot;480&quot;
        alt={product.name}
      /&gt;
    &lt;/div&gt;
  );
}</code></pre><p>getServerSideProps() 함수의 타입은 화살표 함수로 만든 다음에 GetServerSideProps로 지정하면 되고요. 마찬가지로 Props 타입도 정의한 다음, 아래처럼 제네릭으로 지정하고, 페이지 컴포넌트에도 정의하면 됩니다. 이 부분은 자주 쓰일 테니까 기억해 두시면 좋습니다.</p>
<pre><code>
interface Props {
  product: Product;
}

export const getServerSideProps: GetServerSideProps&lt;Props&gt; = async (context) =&gt; {
  // ...
  return {
    props: {
      product,
    },
  };
};

export default function ProductPage({ product }: Props) {
  return (
    &lt;div&gt;
      &lt;h1&gt;{product.name}&lt;/h1&gt;
      &lt;Image
        src={product.imgUrl}
        width=&quot;480&quot;
        height=&quot;480&quot;
        alt={product.name}
      /&gt;
    &lt;/div&gt;
  );
}</code></pre><h2 id="api-라우트">API 라우트</h2>
<p>마지막으로 API 라우트의 타입을 살펴보면 아래와 같이 리퀘스트와, 리스폰스에 타입을 지정하면 됩니다. 어렵지 않죠?</p>
<pre><code>import type { NextApiRequest, NextApiResponse } from &#39;next&#39;

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  // ...
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[11주차 위클리 페이퍼]]></title>
            <link>https://velog.io/@bbobbo-man89/11%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</link>
            <guid>https://velog.io/@bbobbo-man89/11%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</guid>
            <pubDate>Sun, 31 Dec 2023 02:21:41 GMT</pubDate>
            <description><![CDATA[<h1 id="javascript만-사용하는-것과-비교해-typescript를-사용하는-이유에-대해-설명해-주세요">JavaScript만 사용하는 것과 비교해 TypeScript를 사용하는 이유에 대해 설명해 주세요.</h1>
<ol>
<li>정적 타입 체크:
TypeScript는 정적 타입을 지원하여 변수, 함수, 객체 등의 타입을 명시적으로 선언할 수 있습니다.
이는 개발 중에 발생할 수 있는 타입 관련 오류를 미리 방지하고 코드의 안정성을 향상시킵니다.</li>
<li>코드 가이드 및 자동 완성:
IDE에서 TypeScript를 지원하는 경우, 코드 작성 중에 타입 정보에 기반한 가이드와 자동 완성을 받을 수 있습니다.
이는 개발자가 빠르게 코드를 작성하고 오류를 미리 방지하는 데 도움을 줍니다.</li>
<li>유지보수 용이성:
명시적인 타입 선언은 코드를 이해하고 유지보수하는 데 도움을 줍니다.
코드베이스가 커질수록 TypeScript는 코드의 가독성을 높이고 협업을 간소화합니다.</li>
<li>풍부한 인터페이스 및 제네릭 지원:
TypeScript는 인터페이스와 제네릭을 지원하여 추상화 수준을 높이고 코드의 재사용성을 향상시킵니다.</li>
<li>명시적인 API 문서화:
코드에서 명시적인 타입 선언을 사용하면 API의 사용 방법이 명확해지므로 문서 작성이 쉬워집니다.</li>
<li>프로젝트의 확장성:
대규모 프로젝트에서 TypeScript를 사용하면 타입을 통해 코드베이스를 더욱 안정적으로 확장할 수 있습니다.</li>
</ol>
<h1 id="typescript의-동작-원리에-대해-설명해-주세요">TypeScript의 동작 원리에 대해 설명해 주세요.</h1>
<ol>
<li>타입 검사:
TypeScript 컴파일러는 소스 코드를 읽어들여 정적 타입 검사를 수행합니다.
타입 검사에서는 변수, 함수, 객체 등에 대한 타입을 확인하고 불일치가 발견되면 오류를 생성합니다.</li>
<li>컴파일:
TypeScript 파일(.ts 또는 .tsx)은 TypeScript 컴파일러를 통해 JavaScript 파일(.js 또는 .jsx)로 변환됩니다.
이 과정에서 타입 정보는 삭제되며, JavaScript 코드만이 생성됩니다.</li>
<li>실행:
생성된 JavaScript 코드는 브라우저나 Node.js 환경에서 실행됩니다.
브라우저에서 실행되는 경우, 브라우저는 JavaScript 코드를 실행하고 런타임에서 동적 타입을 처리합니다.
TypeScript의 주요 목표는 JavaScript의 확장으로, TypeScript 코드는 JavaScript 코드와 호환되므로 TypeScript를 사용하지 않는 개발자도 동일한 코드베이스에서 작업할 수 있습니다. TypeScript의 타입 정보는 개발자에게 개발 경험을 향상시키고 코드의 안정성을 높이는 데 기여합니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[12주차 위클리 페이퍼]]></title>
            <link>https://velog.io/@bbobbo-man89/12%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</link>
            <guid>https://velog.io/@bbobbo-man89/12%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</guid>
            <pubDate>Sun, 31 Dec 2023 02:18:10 GMT</pubDate>
            <description><![CDATA[<h1 id="리액트만-사용할-때와-비교해-nextjs를-사용하는-이유에-대해-설명해-주세요">리액트만 사용할 때와 비교해 Next.js를 사용하는 이유에 대해 설명해 주세요.</h1>
<h2 id="nextjs-사용-이유">Next.js 사용 이유:</h2>
<ol>
<li>서버 사이드 렌더링(SSR) 및 정적 사이트 생성(SSG) 지원:
Next.js는 기본적으로 SSR 및 SSG를 지원하여 초기 로딩 속도를 개선하고 검색 엔진 최적화(SEO)에 도움을 줍니다.
SSR은 서버에서 페이지를 렌더링하여 클라이언트에 전달하므로 초기 로딩 시간을 줄이고 SEO를 향상시킵니다.
SSG는 미리 렌더링된 정적 파일을 생성하여 서버의 부하를 줄이고 더 빠른 페이지 로딩을 가능하게 합니다.</li>
<li>자동 코드 분할과 코드 최적화:
Next.js는 페이지마다 자동으로 코드를 분할하여 필요한 부분만 로드하므로 초기 로딩 속도가 향상됩니다.
이미지 최적화, 코드 번들링, 트리 쉐이킹 등의 기능을 자동으로 제공하여 개발자가 성능을 최적화하는 데 도움을 줍니다.</li>
<li>Hot Module Replacement (HMR):
개발 중에 코드 수정이 발생하면 브라우저를 새로 고치지 않아도 자동으로 모듈을 교체하여 빠른 개발 환경을 제공합니다.</li>
<li>간편한 API 라우팅 및 파일 시스템 기반의 라우팅:
페이지와 API 라우팅이 파일 시스템 기반으로 간단하게 설정되어 있어 라우팅이 쉽고 직관적입니다.</li>
<li>통합된 CSS 및 CSS-in-JS 지원:
Next.js는 모듈 시스템을 사용하여 CSS 및 CSS-in-JS를 손쉽게 통합할 수 있습니다.</li>
</ol>
<h1 id="nextjs에서-ssr을-실행하는-과정과-hydration에-대해-설명해-주세요">Next.js에서 SSR을 실행하는 과정과 hydration에 대해 설명해 주세요.</h1>
<h2 id="nextjs에서-ssr-실행-및-hydration">Next.js에서 SSR 실행 및 Hydration:</h2>
<ol>
<li>SSR 실행 과정:
사용자가 페이지에 접속하면 Next.js 서버는 해당 페이지의 SSR을 수행합니다.
서버에서는 필요한 데이터를 가져와 페이지를 렌더링한 뒤 HTML로 변환하여 클라이언트에 전송합니다.</li>
<li>Hydration:
클라이언트가 페이지의 HTML을 받으면 JavaScript 코드가 실행되고, 이때 클라이언트에서 React 컴포넌트를 생성합니다.
이후, 서버에서 전송한 HTML과 클라이언트에서 생성한 React 컴포넌트가 일치하는지 확인합니다.
이 과정을 &quot;hydration&quot; 또는 &quot;rehydration&quot;이라고 하며, 렌더링된 페이지를 빠르게 화면에 보여주고 클라이언트에서의 상호작용을 지원합니다.
Next.js는 이러한 과정을 자동으로 처리하여 개발자가 별도로 신경 쓰지 않아도 됩니다. 이를 통해 초기 로딩 성능을 개선하고 사용자 경험을 향상시킬 수 있습니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[8주차 위클리 페이퍼]]></title>
            <link>https://velog.io/@bbobbo-man89/8%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</link>
            <guid>https://velog.io/@bbobbo-man89/8%EC%A3%BC%EC%B0%A8-%EC%9C%84%ED%81%B4%EB%A6%AC-%ED%8E%98%EC%9D%B4%ED%8D%BC</guid>
            <pubDate>Sun, 31 Dec 2023 02:06:29 GMT</pubDate>
            <description><![CDATA[<h1 id="본인이-생각하는-css-in-js의-장점과-단점을-설명해-주세요">본인이 생각하는 CSS-in-JS의 장점과 단점을 설명해 주세요.</h1>
<h2 id="css-in-js">CSS-in-JS?</h2>
<p>CSS-in-JS는 스타일 정의를 css나 scss 파일이 아닌 JavaScript로 작성된 컴포넌트에 바로 삽입하는 스타일 기법이다.</p>
<p>기존 웹사이트는 HTML, CSS, JavaScript를 각자 별도의 파일로 두었는데, React나 Vue, Angluar와 같은 모던 자바스크립트 라이브러리가 인기를 끌고 컴포넌트 기발 개발 방법의 주류가 됨에 따라 한 컴포넌트에 HTML, CSS, JavaScript를 모두 포함하는 패턴이 많이 사용되고 있다.</p>
<h2 id="inline-style-과의-차이점">inline-style 과의 차이점?</h2>
<p>CSS-in-JS는 컴포넌트 안에 css를 정의하는 inline-style과도 비슷한 느낌이다. 하지만 inline-style에는 다음과 같은 단점이 있으므로 inline-style의 사용은 지양하는 것이 좋다.</p>
<h2 id="inline-style의-단점">inline-style의 단점</h2>
<ol>
<li>CSS 속성의 중복, 재사용성이 떨어진다</li>
<li>inline-style로는 의사 클래스, 의사 요소, 미디어 쿼리, 키 프레임 애니메이션 같은 CSS의 기능을 활용할 수 없다</li>
<li>앱의 규모가 커질수록 유지 보수가 어렵다</li>
<li>인라인 스타일이 많으면 코드 가독성이 떨어진다</li>
<li>inline style은 인라인 태그로 style을 정의하는 반면 CSS-in-JS는 style태그를 따로 정의하고 해당 태그에 class화 시켜서 연결 하는 방식으로 동작한다.</li>
</ol>
<p>또 JSX 문법을 사용하는 React의 경우에서는 모든 속성이 props 객체의 일부가 된다. 그러니 style 부분의 비교는 항상 false가 나오게 되고 다시 렌더링 될 때마다 스타일 객체가 다시 계산되어서 성능이 저하될 수 있다.</p>
<h2 id="css-in-js의-장점">CSS-in-JS의 장점</h2>
<ol>
<li>CSS의 컴포넌트화로 스타일시트의 파일을 유지보수 할 필요가 없다. CSS 모델을 문서 레벨이 아닌 컴포넌트 레벨로 추상화한다 (모듈성)
2 .CSS-in-JS는 JavaSript 환경을 최대한 활용 할 수 있다</li>
<li>JavaScript와 CSS 사이의 상수와 함수를 쉽게 공유 할 수 있다</li>
<li>현재 사용중인 스타일만 DOM에 포함한다.</li>
<li>CSS-in-JS는 짧은 길이의 유니크한 클래스를 자동으로 생성하기 때문에 코드 경량화의 장점이 있다</li>
</ol>
<h2 id="css-in-js의-단점">CSS-in-JS의 단점</h2>
<ol>
<li><p>학습 곡선
CSS-in-JS를 처음 사용하는 개발자에게는 학습 곡선이 존재할 수 있습니다. 특히, 기존의 CSS 작성 방식과 다르기 때문에 익숙해지는 데 시간이 걸릴 수 있습니다.</p>
</li>
<li><p>런타임 오버헤드
일부 CSS-in-JS 라이브러리는 런타임에서 스타일을 생성하고 삽입하는 방식을 사용할 수 있습니다. 이로 인해 초기 렌더링 속도에 약간의 오버헤드가 발생할 수 있습니다.</p>
</li>
<li><p>브라우저 호환성
몇몇 CSS-in-JS 솔루션은 특정 브라우저와의 호환성 문제를 가질 수 있습니다. 이는 특히 일부 구식 브라우저에서 문제가 발생할 수 있음을 의미합니다.</p>
</li>
</ol>
<h1 id="presentational--container-디자인-패턴에-대해-설명해-주세요">Presentational &amp; Container 디자인 패턴에 대해 설명해 주세요.</h1>
<p>Presentational &amp; Container 패턴은 React 애플리케이션에서 컴포넌트를 설계하고 구성하는 데 사용되는 디자인 패턴입니다.</p>
<h2 id="presentational-components-ui-components">Presentational Components (UI Components):</h2>
<p>이 컴포넌트들은 주로 UI를 표시하고 스타일링하는 역할을 합니다. 데이터나 상태를 직접 관리하지 않으며, 부모로부터 전달된 props를 받아 렌더링합니다. Presentational 컴포넌트는 주로 재사용성이 높고, 스타일과 레이아웃에 중점을 둡니다.</p>
<pre><code>// 예시: Presentational 컴포넌트
const Button = ({ onClick, label }) =&gt; (
  &lt;button onClick={onClick}&gt;{label}&lt;/button&gt;
);</code></pre><h2 id="container-components">Container Components:</h2>
<p>이 컴포넌트들은 주로 상태와 로직을 관리합니다. 데이터를 가져오고 상태를 업데이트하며, 이 정보를 Presentational 컴포넌트에 전달합니다. Container 컴포넌트는 주로 어플리케이션의 상태를 관리하고, Presentational 컴포넌트들을 조율하여 완성된 화면을 구성합니다.</p>
<pre><code>// 예시: Container 컴포넌트
class ButtonContainer extends React.Component {
  state = {
    count: 0,
  };

  handleClick = () =&gt; {
    this.setState(prevState =&gt; ({ count: prevState.count + 1 }));
  };

  render() {
    return &lt;Button onClick={this.handleClick} label={`Clicked: ${this.state.count} times`} /&gt;;
  }
}</code></pre><p>이러한 패턴을 사용하면 코드를 더 쉽게 유지보수하고 테스트할 수 있습니다. Presentational 컴포넌트는 UI에 집중하고, Container 컴포넌트는 데이터와 로직에 집중하여 역할을 분리함으로써 개발자는 각각의 역할에 집중할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Typescript -tsconfig.json설정]]></title>
            <link>https://velog.io/@bbobbo-man89/Typescript-tsconfig.json%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@bbobbo-man89/Typescript-tsconfig.json%EC%84%A4%EC%A0%95</guid>
            <pubDate>Fri, 29 Dec 2023 00:43:35 GMT</pubDate>
            <description><![CDATA[<p>앞에서 프로젝트를 만들 때 tsc --init 명령어로 tsconfig.json 파일을 생성했습니다. 아래와 같은 파일이 생성되었는데요.  이번 레슨에서는 이 파일에서 사용할 수 있는 옵션들에 대해서 좀 더 자세히 살펴보겠습니다.</p>
<pre><code>
{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;es2016&quot;,                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    &quot;module&quot;: &quot;commonjs&quot;,                                /* Specify what module code is generated. */
    &quot;esModuleInterop&quot;: true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables &#39;allowSyntheticDefaultImports&#39; for type compatibility. */
    &quot;forceConsistentCasingInFileNames&quot;: true,            /* Ensure that casing is correct in imports. */
    &quot;strict&quot;: true,                                      /* Enable all strict type-checking options. */
    &quot;skipLibCheck&quot;: true                                 /* Skip type checking all .d.ts files. */
  }
}</code></pre><h3 id="꼭-알아야-할-컴파일러-옵션들">꼭 알아야 할 컴파일러 옵션들</h3>
<p>compilerOptions에서 사용할 수 있는 옵션 중에서 중요한 것들을 살펴보겠습니다.</p>
<h3 id="target-어떤-ecmascript-버전으로-변환할지">target: 어떤 ECMAScript 버전으로 변환할지</h3>
<p>타입스크립트 코드는 빌드해서 자바스크립트로 변환하는데요. 이때 변환할 자바스크립트의 버전을 정할 수 있습니다. 만약에 프로젝트가 과거 자바스크립트 표준만 지원하는 브라우저까지 지원해야 한다면, 여기서 오래된 버전을 설정할 수 있죠. 2023년 현재를 기준으로 tsconfig.json을 생성했을 때는, 기본적으로는 ES7(ES2016)으로 변환하도록 되어있습니다. 여기다가 ES6(ES2015)나 ES3 등을 설정해 줄 수 있습니다.</p>
<p>코드를 실행할 브라우저나 Node.js 환경에 따라 선택하시면 되는데요. 브라우저의 경우 ES5는 거의 모든 브라우저에서 지원하고, ES6는 인터넷 익스플로러를 제외하면 대부분의 브라우저에서 지원합니다. Node.js의 경우 v14 이후 버전을 쓰신다면 ES5, ES6를 대부분 지원합니다.</p>
<p>잘 모르겠다면 일단은 ES6로 설정해 두고 쓰시는 걸 추천드릴게요. 실행 환경에 따른 문법 지원 여부가 궁금하신 분들은 아래 두 링크를 참고해 보세요.</p>
<p><a href="https://caniuse.com/?search=ECMAScript">&quot;ECMAScript&quot; | Can I use... Support tables for HTML5, CSS3, etc</a>
ECMAScript 6 compatibility table (kangax.github.io)</p>
<h3 id="module-어떤-방식으로-모듈을-만들지">module: 어떤 방식으로 모듈을 만들지</h3>
<p>자바스크립트 모듈에는 크게 두 가지 방식이 있습니다. ES6부터 도입된 import/export 문법을 사용하는 ESM(ECMAScript Module) 방식이 있고요, Node.js 같은 데서 기본적으로 사용하는 CJS(CommonJS) 방식이 있는데요.</p>
<p>이 옵션에서는 자바스크립트 코드로 트랜스파일할 때 어떤 모듈 문법으로 변환할지 선택할 수 있습니다. 다양한 옵션 값을 지원하는데요. ESM을 쓰시려면 es6, es2020 같이 es로 시작하는 값을 쓰면 되고, CJS를 쓰시려면 commonjs라고 쓰시면 됩니다.</p>
<p>보통 Node.js 환경에서는 CJS를 사용하고, 프론트엔드 개발을 할 때는 보통 번들러에서 모듈을 알아서 처리해 주기 때문에 ESM, CJS 상관없이 쓰실 수 있을 겁니다. 어떤 걸 선택할지 잘 모르겠다면 commonjs로 설정하는 걸 추천드릴게요.</p>
<h3 id="esmoduleinterop-es-모듈을-안전하게-사용">esModuleInterop: ES 모듈을 안전하게 사용</h3>
<p>ESM 문법에서 import * as moment from &#39;moment&#39;라든가 import moment from &#39;moment&#39;라는 문법은 서로 다른데요. 이 옵션을 false로하면 CJS로 변환했을 때 두 코드는 같은 형태의 코드 const moment = require(&#39;moment&#39;)로 변환됩니다. 안전하게 모듈을 사용하려면 esModuleInterop 옵션은 true로 해놓는 것을 권장드립니다.</p>
<p><a href="https://www.typescriptlang.org/ko/tsconfig#esModuleInterop">TypeScript: TSConfig Reference - Docs on every TSConfig option (typescriptlang.org)</a></p>
<h3 id="forceconsistentcasinginfilenames-파일의-대소문자-구분하기">forceConsistentCasingInFileNames: 파일의 대소문자 구분하기</h3>
<p>macOS를 사용하시는 분들은 main.ts라는 파일과 Main.ts라는 파일이 서로 다른데요. Windows와 같이 어떤 운영체제에서는 종종 main.ts라는 파일과 Main.ts라는 파일을 동일하게 취급하기도 합니다. 이런 환경에서 개발하더라도 반드시 대소문자 구분을 명확하게 하겠다는 옵션입니다. 이 옵션도 반드시 true로 해 놓는 걸 권장드립니다.</p>
<h3 id="strict-엄격한-규칙들-켜기">strict: 엄격한 규칙들 켜기</h3>
<p>이 옵션을 켜면 stict와 관련된 여러 규칙들을 한꺼번에 켤 수 있는데요. 어떤 옵션들이 켜지는지는 공<a href="https://www.typescriptlang.org/tsconfig#strict">식 문서의 strict 옵션</a> 설명을 참고해 주세요. 여기서는 그중에서도 대표적으로 알아두면 좋은 것 두 가지를 소개해드리겠습니다.</p>
<p>noImplicitAny: 아무 타입을 직접 정의하지 않고, 타입 추론도 되지 않는 상태를 implicit any라고 하는데요. 쉽게 말해서 기존 자바스크립트 코드처럼 타입 없이 사용하는 걸 implicit any라고 합니다.</p>
<pre><code>function printSize(product) {
                   ~~~~~~~ 타입 정의도 없고 추론할 수도 없음
  console.log(product.size);
}</code></pre><p>새로 시작하는 타입스크립트 프로젝트라면 무조건 켜는 걸 추천드리지만, 기존에 자바스크립트로 만든 프로젝트를 타입스크립트로 옮기는 중이라면 이 옵션을 잠시 끄는 것도 좋습니다. 아래처럼 설정하면 strict 규칙들을 한꺼번에 설정하지만 noImplicitAny는 설정하지 않을 수 있습니다.</p>
<pre><code>&quot;strict&quot;: true,
&quot;noImplicitAny&quot;: false,</code></pre><p>strictNullChecks: null이 될 가능성이 있다면, 이런 경우를 반드시 처리하도록 하는 옵션입니다. 이것도 되도록이면 켜 놓으시는 걸 추천합니다. 예를 들자면 아래와 같은 코드는 strict null check를 할 때는 오류가 납니다. num 변수가 null이 될 수도 있으니까요. 반면에 strictNullChecks가 꺼져있다면 타입 오류가 나지 않습니다. 대신에 실행하는 도중에 num 변수에 null 값이 들어간다면 런타임 오류가 나겠죠?</p>
<pre><code>let num: number | null;
// ...
num -= 1;
~~~</code></pre><p>되도록이면 strictNullChecks를 켜시고, 이런 경우에는 반드시 null check를 하는 걸 권장드립니다.</p>
<pre><code>
let num: number | null;
// ...
if (num !== null) {
  num -= 1;
}</code></pre><h3 id="skiplibcheck-설치한-패키지의-타입-검사하지-않기">skipLibCheck: 설치한 패키지의 타입 검사하지 않기</h3>
<p>node_modules 폴더에 설치된 패키지들의 타입 검사를 하지 않는 옵션입니다. 패키지 개발 과정에서 대부분 타입 검사가 이뤄지기 때문에, 중복으로 하지 않아도 됩니다. 그래서 이 옵션을 사용하시길 추천드립니다.</p>
<h3 id="rootdir-최상위-폴더">rootDir: 최상위 폴더</h3>
<p>타입스크립트 컴파일러가 처리할 타입스크립트 파일들의 최상위 폴더를 정하는 옵션입니다. 기본 값으로는 처리하는 파일들의 경로를 종합해서 최상위 폴더를 정합니다. 만약 tsconfig.json 파일과 같은 폴더에 있는 src 폴더를 최상위 폴더로 정하고 싶다면 아래와 같이 쓰면 됩니다.</p>
<pre><code>
{  
  &quot;compilerOptions&quot;: {
    &quot;rootDir&quot;: &quot;src&quot;,
  }
}</code></pre><h3 id="outdir-자바스크립트-파일을-생성할-폴더">outDir: 자바스크립트 파일을 생성할 폴더</h3>
<p>outDir에 지정된 폴더 안에다가 rootDir의 디렉토리 구조에 따라서 자바스크립트 파일을 만듭니다. 값을 지정하지 않으면 소스코드 파일과 같은 폴더에 자바스크립트 파일을 만듭니다.</p>
<pre><code>{  
  &quot;compilerOptions&quot;: {
    &quot;outDir&quot;: &quot;dist&quot;,
  }
}</code></pre><h3 id="resolvejsonmodule-json-파일-임포트하기">resolveJsonModule: JSON 파일 임포트하기</h3>
<p>.json 파일을 임포트해서 사용하고 싶다면 이 옵션을 켜야 합니다.</p>
<pre><code>import data from &#39;data.json&#39;;
// ...</code></pre><h3 id="include와-exclude">include와 exclude</h3>
<p>tsc로 트랜스파일할 때 포함할 경로(include)와 포함하지 않을 경로(exclude)를 정해줄 수 있습니다. 배열로 경로 패턴을 적어주면 되는데요. *<em>/</em>라는 코드는 아래의 모든 폴더, 모든 파일을 의미합니다. 참고로 이런 패턴을 Glob 패턴이라고 합니다. 혹시 궁금하신 분들은 위키피디아 Glob 문서를 참고해 보세요.</p>
<pre><code>
{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;es2016&quot;,                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    &quot;module&quot;: &quot;commonjs&quot;,                                /* Specify what module code is generated. */
    &quot;esModuleInterop&quot;: true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables &#39;allowSyntheticDefaultImports&#39; for type compatibility. */
    &quot;forceConsistentCasingInFileNames&quot;: true,            /* Ensure that casing is correct in imports. */
    &quot;strict&quot;: true,                                      /* Enable all strict type-checking options. */
    &quot;skipLibCheck&quot;: true                                 /* Skip type checking all .d.ts files. */
  }
  &quot;include&quot;: [&quot;src/**/*&quot;, &quot;tests/**/*&quot;],
  &quot;exclude&quot;: [&quot;bin/**/*&quot;],
}</code></pre><h3 id="그-밖의-옵션들-활용하기">그 밖의 옵션들 활용하기</h3>
<p>옵션이 너무 많기 때문에 모든 옵션들을 전부 알고 있을 필요는 없습니다. 그 밖의 다른 옵션들이 궁금하신 분들은 <a href="https://www.typescriptlang.org/tsconfig">타입스크립트 공식 문서</a>를 참고하시는 걸 추천드립니다.</p>
<p>참고로 VS Code에서는 옵션들을 자동완성 기능으로 작성할 수 있는데요. 무엇을 작성해야 할지 모를 때 Windows에서는 Ctrl + I, macOS에서는 Cmd + I를 입력하면 Suggestion이 뜹니다. 각 옵션에 대한 설명도 볼 수 있으니까 공부 목적이 아니라 프로젝트를 개발할 때는 이 기능을 활용하시는 걸 추천합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Typescript 문법 정리]]></title>
            <link>https://velog.io/@bbobbo-man89/Typescript-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@bbobbo-man89/Typescript-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 28 Dec 2023 13:07:19 GMT</pubDate>
            <description><![CDATA[<h1 id="리터럴-타입">리터럴 타입</h1>
<p>특정한 숫자나 문자열 같이 변수의 값을 타입으로 하는 타입입니다. 각 리터럴 타입들은 string이나 number 같은 더 큰 타입에 포함됩니다.</p>
<pre><code>
const name = &#39;codeit&#39;; // &#39;codeit&#39; 이라는 리터럴 타입
const rank = 1; // 1 이라는 리터럴 타입</code></pre><h1 id="타입-별칭">타입 별칭</h1>
<p>복잡한 타입에 이름을 붙이고 재사용하고 싶을 때 사용합니다.</p>
<pre><code>type Point = [number, number];
type SearchQuery = string | string[];
type Result = SuccessResult | FailedResult;
type Coupon = 
  | PromotionCoupon
  | EmployeeCoupon
  | WelcomCoupon
  | RewardCoupon
  ;   </code></pre><h1 id="union">Union</h1>
<p>A이거나 또는 B인 경우를 타입으로 만들고 싶을 때</p>
<pre><code>ClothingProduct | ShoeProduct</code></pre><h1 id="intersection">Intersection</h1>
<p>A와 B의 성질을 모두 갖는 타입을 만들고 싶을 때</p>
<pre><code>interface Entity {
  id: string;
  createdAt: Date;
  updatedAt: Date;
}

type Product = Entity &amp; {
  name: string;
  price: number;
  membersOnly?: boolean;
}</code></pre><p>하지만 보통 이럴 때는 interface와 상속을 사용하시는 걸 권장드립니다.</p>
<pre><code>interface Entity {
  id: string;
  createdAt: Date;
  updatedAt: Date;
}

interface Product extends Entity {
  name: string;
  price: number;
  membersOnly?: boolean;
}</code></pre><h1 id="keyof-연산자">keyof 연산자</h1>
<p>객체 타입에서 프로퍼티 이름들을 모아서 Union한 타입으로 만들고 싶을 때 사용합니다.</p>
<pre><code>interface Product {
  id: string;
  name: string;
  price: number;
  membersOnly?: boolean;
}

type ProductProperty = keyof Product; // &#39;id&#39; | &#39;name&#39; | &#39;price&#39; | &#39;membersOnly&#39;;</code></pre><h1 id="typeof-연산자">typeof 연산자</h1>
<p>자바스크립트 코드에서 사용하면 결괏값이 문자열이지만, 타입스크립트 코드에서 쓸 때는 결과 값은 타입스크립트의 타입입니다.</p>
<pre><code>const product: Product = {
  id: &#39;c001&#39;,
  name: &#39;코드잇 블랙 후드 집업&#39;,
  price: 129000,
  salePrice: 98000,
  membersOnly: true,
};

console.log(typeof product); // 문자열 &#39;object&#39;

const product2: typeof product = { // 타입스크립트의 Product 타입
  id: &#39;g001&#39;,
  name: &#39;코드잇 텀블러&#39;,
  price: 25000,
  salePrice: 19000,
  membersOnly: false,
};</code></pre>]]></description>
        </item>
    </channel>
</rss>