<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>juiuj</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 06 Feb 2026 14:23:06 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>juiuj</title>
            <url>https://velog.velcdn.com/images/dev-joohee/profile/479ba630-7c1a-4fea-a7c0-3b65868cd44f/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. juiuj. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev-joohee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[웹배포] Docker는 왜 필요했을까]]></title>
            <link>https://velog.io/@dev-joohee/%EC%9B%B9%EB%B0%B0%ED%8F%AC-Docker%EB%8A%94-%EC%99%9C-%ED%95%84%EC%9A%94%ED%96%88%EC%9D%84%EA%B9%8C</link>
            <guid>https://velog.io/@dev-joohee/%EC%9B%B9%EB%B0%B0%ED%8F%AC-Docker%EB%8A%94-%EC%99%9C-%ED%95%84%EC%9A%94%ED%96%88%EC%9D%84%EA%B9%8C</guid>
            <pubDate>Fri, 06 Feb 2026 14:23:06 GMT</pubDate>
            <description><![CDATA[<p>처음 프로젝트를 진행하며 EC2 배포를 해봤을 때의 기억은 대체로 비슷하다.. Node 버전 설치하고,, 패키지 설치하고,, 환경 변수 맞추고,,포트 열고,, 뭐 어찌저찌 하면 일단 돌아가는 서버(..)는 만들어진다.</p>
<p>문제는 그 다음부터다.
EC2 배포를 한 번이라도 해봤다면, 아래 상황 중 하나 쯤은 겪어봤을 가능성이 높다 🤯</p>
<ul>
<li>로컬에서는 잘 되던 앱이 서버에서는 에러 남;</li>
<li>분명 어제까지 되던 코드가 오늘 서버에서는 안된다;;</li>
<li>같은 레포를 다른 EC2에 올렸는데 결과가 다름;;;
<del>나같경 다 겪어봄;;;;;;;;;;;;</del></li>
</ul>
<p>이때 우리가 흔하게 하는 말이 있다
&quot;아마 서버 환경이 달라서 그런 거 같아요..&quot;
이 말인 즉슨, 문제의 원인이 코드가 아니라 환경일 수도 있다는 사실이다 💦</p>
<p>지금부터 알아보려는 <code>Docker</code>는 위와 같은 상황에 대하여 <strong>코드 뿐만 아니라 실행 환경 자체를 함께 관리할 수는 없을까?</strong> 라는 질문에 대한 답으로 등장했다.</p>
<hr>
<h1 id="docker란">Docker란?</h1>
<p><code>Docker</code>를 한 문장으로 정의하자면 이렇게 말할 수 있다👇👇👇</p>
<blockquote>
<p><strong>애플리케이션과 그 실행 환경을 하나로 묶어서 어디서든 같은 조건으로 실행되게 만드는 기술</strong></p>
</blockquote>
<h2 id="vm-vs-docker---뭐가-다른가">VM vs Docker - 뭐가 다른가?!</h2>
<p>우선 VM(VirtualMachine)부터 보자!
<code>VM</code>은 하나의 서버 위에 또 다른 완전한 서버를 통째로 올리는 방식이라 볼 수 있다.
즉, 애플리케이션을 실행하기 위해 필요한 것뿐만 아니라 <strong>운영체제(OS)까지 함께 포함해서 하나의 가상 머신</strong>으로 만든다.</p>
<p>🙋‍♀️ 그 결과, 각 VM은 독립적인 OS를 가지게 되는데 .. 그만큼 부팅이 느리고, 자원 사용량이 커지게 된다.
환경이 완전히 분리된다는 안정성은 있지만,, 무거워지는 건 어쩔 수 없다;</p>
<p><strong>❗️반면에❕</strong>
<code>Docker</code>는 접근 방식이 다르다.
VM과 달리 OS를 새로 만들지 않고, *<code>호스트 OS</code>를 여러 *<code>컨테이너</code>가 공유한다. 
즉, OS는 공유하고, 실행 환경만 분리함!</p>
<p>그래서 OS를 포함하지 않기 때문에 가볍고, 바로 실행할 수 있어서 빠르며, 같은 환경을 여러 곳에 쉽게 복제할 수도 있다.</p>
<p>*호스트 OS: Docker나 VM을 실행하고 있는 찐또배기 운영체제
*컨테이너는 아래에서 설명</p>
<h2 id="컨테이너-이미지">컨테이너? 이미지?</h2>
<p><code>Docker</code> 이야기를 어렵게 만드는 단어가 바로 <code>이미지</code>와 <code>컨테이너</code>이다.
이게 뭐인고 싶어서 공식 정의부터 보면 오히려 더 헷갈린다;</p>
<p>지피티왈,</p>
<ul>
<li>이미지: 애플리테이션이 실행되기 위한 환경의 설계도</li>
<li>컨테이너: 그 설계도로부터 실제로 실행 중인 결과물</li>
</ul>
<p>로 이해하면 된단다.</p>
<p>조금 더 이해하기 쉽게는,
<code>이미지</code>는 &quot;이 앱은 이런 환경에서 실행돼야 해&quot; 라고 적어둔 <strong>묶음 설명서</strong>고, <code>컨테이너</code>는 그 설명서를 기반으로 실제로 떠 있는 <strong>실행 상태의 앱</strong>이다.</p>
<h3 id="ec2-배포의-경험이랑은-어떻게-이어볼-수-있으까">EC2 배포의 경험이랑은 어떻게 이어볼 수 있으까</h3>
<p>EC2에 직접 배포할 때를 떠올려보면 우리는 보통 아래와 같은 과정을 거친다👇</p>
<blockquote>
<p>서버에 접속 -&gt; Node버전 맞추기 -&gt; 패키지 설치 -&gt; 환경 변수 설정 -&gt; &quot;이 서버에서는 이렇게 돌아가게 하자&quot;는 결정(?)</p>
</blockquote>
<p>이 모든 과정이 사실상 <code>이미지</code>를 손으로 만들고 있던 셈이다..🤯
다만 그 이미지가 코드로 남아 있지 않고 서버 안에서만 흩어져 있었을 뿐..</p>
<p><img src="https://velog.velcdn.com/images/dev-joohee/post/d0114eb7-1577-431c-a705-339f1fde11b2/image.png" alt=""></p>
<p>docker는 이 과정을 뒤집어서 &quot;이 서버에서 뭘 설치하지?&quot;가 아니라 <strong>&quot;이 앱이 실행되기 위해서 필요한 환경은 뭐지?&quot;</strong> 를 먼저 정의한다!</p>
<p>그 정의가 <code>이미지</code>가 되고, 그 이미지를 실행한 결과가 <code>컨테이너</code>다<em>!</em></p>
<blockquote>
<p>기존(EC2)에는 &quot;이 EC2에서 이 코드가 잘 돌게 만들자&quot; 였다면, Docker 이후에는 <strong>&quot;어디서든 이 이미지를 실행하면 같은 결과가 나오게 만들자&quot;</strong>가 된다</p>
</blockquote>
<p>그래서 Docker를 쓰는 배포는 서버에 의존하는 작업이 아니라 <strong>실행 환경을 전달하는 작업</strong>에 가깝다❕</p>
<hr>
<h3 id="docker는-실제로-어디에서-쓰일까">Docker는 실제로 어디에서 쓰일까?</h3>
<p>여기까지 읽었다면, Docker가 단순히 로컬 개발용 도구가 아니라 <strong>배포와 실행 환경을 다루는 방식 자체를 바꾸는 기술</strong> 라는 건 감이 왔을 것이다!</p>
<p>그래서 Docker는 주로 아래와 같은 상황에서 쓰인다 👇</p>
<blockquote>
<ul>
<li>개발자마다 다른 환경에서 작업하던 문제를 줄이고 싶을 때</li>
</ul>
</blockquote>
<ul>
<li>서버가 여러 대로 늘어나면서 환경 재현이 어려워질 때</li>
<li>배포 과정을 사람의 손이 아니라 규칙으로 관리하고 싶을 때</li>
</ul>
<p>이때 docker는 &quot;서버마다 설정을 맞추자&quot;가 아니라 <strong>&quot;이 이미지를 어디서나 실행하자&quot;</strong>라는 선택지를 만든다!
.
.
그 이후부터는 또 다른 도구들이 자연스럽게 쓰이는데 그건 기회가 되면 다른 글에서 다뤄보겠다.</p>
<hr>
<p>Docker를 공부하며 모 유튜버의 영상을 참고했는데 요즘앤 코딩 처음 시작할 때 Docker 설치부터 배운다고 하던데..
수동 배포를 겪어봐야 하는데 도커부터 배우는 점이 안타깝다고 하던데 그 부분엔 나도 약간 동의.
수동배포하면서 참교육을 당하고 나면 도커가 더더더 고트하게 느껴질 것 같다
끝</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹보안] 왜 HttpOnly / SameSite / Secure 같은 옵션이 필요한가?]]></title>
            <link>https://velog.io/@dev-joohee/%EC%9B%B9%EB%B3%B4%EC%95%88-%EC%99%9C-HttpOnly-SameSite-Secure-%EA%B0%99%EC%9D%80-%EC%98%B5%EC%85%98%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80</link>
            <guid>https://velog.io/@dev-joohee/%EC%9B%B9%EB%B3%B4%EC%95%88-%EC%99%9C-HttpOnly-SameSite-Secure-%EA%B0%99%EC%9D%80-%EC%98%B5%EC%85%98%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80</guid>
            <pubDate>Thu, 05 Feb 2026 08:07:35 GMT</pubDate>
            <description><![CDATA[<p>최근 <a href="https://wayout.kr/">WAyout 프로젝트</a>를 진행하며 개발이란 파면 팔 수록.. 공부할 게 정말 많다는 생각이 끝없이 든다. 프론트엔드로서 프로젝트를 진행하며 가장 취약하다고 느낀 부분은 바로 <strong>웹보안, 웹인증</strong> 관련 부분인데, 팀원들이 관련해서 질문을 할 때마다 식은땀이 줄줄 흐른다...;;;ㅜㅜ😅</p>
<p>오늘 공부해 볼 부분은 <strong>⌜왜 HttpOnly / SameSite / Secure 같은 옵션이 필요한가?⌟</strong> 이다.</p>
<p>이 공부를 통해서 쿠키 옵션 3개가 각각 어떤 공격을 막는지 한 번에 이해하고, 우리 서비스에서 쿠키를 쓴다면 어떤 조합으로 설정해야 하는 지 판단을 명확하게 할 수 있었으면 좋겠다<em>!</em></p>
<hr>
<h2 id="왜-쿠키-옵션-이야기를-해야-할까">왜 쿠키 옵션 이야기를 해야 할까?</h2>
<p>요즘 인증 구조를 보면 <code>OAuth 로그인</code>, 서버에서 <code>AccessToken</code>, <code>RefreshToken</code> 발급 -&gt; 토큰을 쿠키에 저장 -&gt; 브라우저는 요청마다 쿠키를 자동으로 전송...</p>
<p>문제는 여기서 끝이 아니다.</p>
<p>쿠키는 기본적으로 <strong>브라우저에 저장</strong>되고, 요청 시 자동으로 전송되며 설정을 잘못하면 <strong>보안 공격의 타깃</strong>이 될 수도 있다;;</p>
<p>그래서 등장한 게 바로
<code>HttpOnly</code>, <code>SameSite</code>, <code>Secure</code> 옵션이다.</p>
<p>쉽게 말해서 이 옵션들은 &quot;쿠키를 쓸 순 있는데, 아무렇게 쓰지는 말자~&quot;를 구현한 안전 장치 같은 거라고 볼 수 있다.</p>
<hr>
<h1 id="httponly란---js는-쿠키-건드리지말거라">HttpOnly란? - &quot;JS는 쿠키 건드리지말거라&quot;</h1>
<p><code>HttpOnly</code>는 말 그대로 <strong>JavaScript에서 쿠키에 접근하지 못하게 하는 옵션</strong> 이다.</p>
<h2 id="httponly-옵션이-왜-필요할까">HTTPOnly 옵션이 왜 필요할까?</h2>
<p><strong>&lt;XSS에서 토큰이 털리는 과정..&gt;</strong>
토큰이 JS에서 읽히는 위치에 있으면 *<code>XSS</code> 발생 시 토큰이 복제되어 탈취될 가능성이 매우 높다..!
즉, 토큰이 쿠키에 있어도 JS에서 읽을 수 있으면 XSS가 한방에 끝이다ㅜㅜ😭</p>
<p>*XSS: 공격자가 웹사이트에 악성 JavaScript를 주입해, 해당 사이트 사용자 권한으로 스크립트를 실행하게 만드는 취약점</p>
<p>그래서 인증 토큰을 쿠키에 넣는다면 <strong>HttpOnly는 거의 필수</strong>라고 볼 수 있다!</p>
<blockquote>
<p><code>HttpOnly</code>는 <strong>JS 접근 차단</strong>하고, XSS로부터 <strong>토큰 직접 탈취를 방어</strong>한다.
프론트에서 토큰을 읽을 수 없게 만드는 대신, 인증 판단은 서버나 응답 결과 기반으로 처리해야 한다!</p>
</blockquote>
<hr>
<h1 id="secure란---https에서만-보내라">Secure란? - &quot;HTTPS&quot;에서만 보내라</h1>
<p><code>Secure</code>옵션이 있으면 쿠키는 HTTP 요청에서는 포함되지 않고, <strong>HTTPS</strong> 요청에서만 전송된다.</p>
<h2 id="secure-옵션이-왜-필요할까">Secure 옵션이 왜 필요할까?</h2>
<p>이를 이해하기 위해선 HTTP와 HTTPS의 특징을 파악해야 한다.
지난 <a href="https://velog.io/@dev-joohee/HTTP%EC%99%80-HTTPS%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90">HTTPS 공부</a>를 참고하자~~</p>
<p>간단하게 살펴보자면,
HTTP는 암호화가 없어서 네트워크 구간에서 <strong>트래픽이 노출</strong>될 수 있다. 이때 쿠키가 평문으로 오가면 중간자 공격/스니핑 같은 방식으로 <strong>쿠키가 그대로 탈취될 위험</strong>이 있다.
그래서 전송 중 데이터 암호화가 가능한 <code>HTTPS</code>를 사용하게 되는데, <code>Secure</code>은 그 <strong>암호화 된 통신에서만 쿠키를 쓰겠다</strong> 라는 선언과 같은 것이다.</p>
<p>🙋‍♀️ 그래서 운영 환경에서는 사실상 <strong>쿠키 인증이면 Secure는 기본</strong>이라고 생각해도 좋을 것 같다.</p>
<hr>
<h1 id="samesite란---어디서-온-요청인지-살펴보자">SameSite란? - &quot;어디서 온 요청인지 살펴보자&quot;</h1>
<p><code>SameSite</code>는 이 쿠키가 어떤 도메인에서만 사용할 수 있는지 설정할 수 있는 옵션으로, <code>CSRF</code> 공격 방어와 관련되어 있다.</p>
<h3 id="왜-필요할까-csrf">왜 필요할까? (CSRF)</h3>
<blockquote>
<p>쿠키는 &quot;출처를 가리지 않고&quot; 자동 전송된다.</p>
</blockquote>
<p>즉, 사용자가 로그인된 상태일때 다른 사이트에서 요청이 발생할 경우, 조건만 맞으면 <strong>브라우저에서 쿠키가 같이 전송</strong>될 수 있다.</p>
<h2 id="samesite-옵션-3종류-👀">SameSite 옵션 3종류 👀</h2>
<p><strong>1️⃣ SameSite = Strict</strong>
다른 사이트에서 온 요청은 수락하지 않고, <strong>같은 사이트에서만 전송</strong>하는 옵션이다. (반드시 같은 도메인에서만 사용 가능)
Strict를 보면 알 수 있듯이 가장 강력해서 외부 링크, OAuth 리다이렉트에도 쿠키가 안 붙는다.
인증 흐름에서는 불편할 수 있지만, 보안은 최고❗️ <del>UX는 최악</del></p>
<p><strong>2️⃣ SameSite = Lax</strong> (기본값)
같은 도메인에서만 사용 가능하지만, <strong>유저가 링크를 클릭해서 접속하거나 하는 경우</strong>에는 <strong>다른 도메인에서도 사용 가능</strong>하다!
대부분의 CSRF 공격을 차단하고, 일반적인 로그인 유지에 적합해서 요즘 가장 많이 쓰이는 옵션이다.</p>
<p><strong>3️⃣ SameSite = None</strong>
다른 도메인에서도 사용 가능하며, 모든 요청에 쿠키를 전송한다. 그래서 OAuth, 서브도메인, 외부 인증에서 사용 가능하다.
ex) auth.google.com -&gt; wayout.kr(리다이렉트) 와 같은 경우에 사용할 수 있다!</p>
<h3 id="반드시️">반드시‼️</h3>
<blockquote>
<p><strong><code>Secure = True</code></strong>와 함께 써야 한다. (Secure가 없으면 브라우저가 쿠키를 아예 거부한다.)
<code>SameSite = None</code>은 사실상 CSRF 방어를 포기하는 선택이라서 브라우저가 <strong>암호화된 HTTPS 환경에서만 허용</strong>하도록 강제한다..!</p>
</blockquote>
<hr>
<p>쿠키 기반 인증은 편하지만, 옵션 없이 쓰는 쿠키 인증은 위험하다.
<code>HttpOnly</code>/<code>Secure</code>/<code>SameSite</code>는 쿠키를 제대로 쓰기 위한 최소한의 안전장치 같은 거라서 꼭 활용하도록 해야겟슨.</p>
<p>마무리는 어젯밤에 먹은 초코칩쿠키사진이다
<img src="https://velog.velcdn.com/images/dev-joohee/post/4ad039f2-0309-4528-b805-43eb76c948d4/image.jpeg" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹보안] HTTP와 HTTPS의 차이점을 알아보자!]]></title>
            <link>https://velog.io/@dev-joohee/HTTP%EC%99%80-HTTPS%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev-joohee/HTTP%EC%99%80-HTTPS%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 03 Feb 2026 07:56:53 GMT</pubDate>
            <description><![CDATA[<p>웹 개발을 하다보면 URL 앞에 항상 붙는 <code>http://</code>, <code>https://</code>를 보게 된다.
겉보기에는 단순히<code>s</code> 하나 차이지만, 어떤 차이점이 있길래 <code>https</code>를 주로 쓰는걸까?</p>
<h1 id="http란-무엇인가">HTTP란 무엇인가?</h1>
<p><strong>HTTP(HyperText Transfer Protocol)</strong>는 클라이언트(브라우저)와 서버가 데이터를 주고 받기 위한 규칙(프로토콜)이다.</p>
<p>HTTP는 데이터를 <strong>✌️암호화하지 않고✌️</strong> 평문 그대로 전송하기 때문에 네트워크 중간에서 데이터가 그대로 노출될 수 있다. 그 때문에 <code>로그인 정보</code>, <code>개인정보</code>가 탈취될 위험이 존재한다.</p>
<blockquote>
<p>공용 와이파이 환경에서 HTTP 사이트에 로그인하면 아이디와 비밀번호가 <strong>그대로 노출</strong>💦 될 수 있음</p>
</blockquote>
<p>그래서 HTTP는 <strong>보안에 취약</strong>하다.</p>
<hr>
<h1 id="https란-무엇인가">HTTPS란 무엇인가?</h1>
<p>HTTPS의 <code>s</code>는 <code>secure</code>로, HTTP에 *<em>보안 계층(SSL/TLS) *</em>을 추가한 프로토콜이다.</p>
<p>HTTPS는 데이터가 <code>암호화되어 전송</code>되고, 그로 인해 중간에서 가로채도 내용을 해독할 수 없다는 특징이 있다. 또한 SSL/TLS 인증서와 CA를 통해 서버의 신뢰성 검증이 가능하다는 장점이 있다.
<del>닉값하는 프로토콜</del></p>
<h3 id="ssltls-인증서란">SSL/TLS 인증서란?</h3>
<p>SSL/TLS 인증서는 쉽게 말해 &quot;이 서버는 신뢰할 수 있는 서버&quot; 라는 것을 증명하는 전자 신분증 같은 거라고 볼 수 있다.</p>
<blockquote>
<p><strong>🔐 SSL</strong></p>
</blockquote>
<ul>
<li>SSL (Secure Sockets Layer)
  → 보안 소켓 계층</li>
<li>클라이언트와 서버 사이의 통신을 암호화하기 위해 만들어진 보안 프로토콜</li>
<li>HTTPS의 초기 보안 기술</li>
<li>현재는 보안 취약점 때문에 더 이상 사용되지 않음</li>
</ul>
<blockquote>
<p><strong>🔐 TLS</strong></p>
</blockquote>
<ul>
<li>TLS (Transport Layer Security)
  → 전송 계층 보안</li>
<li>SSL을 개선한 최신 보안 프로토콜</li>
<li>현재 HTTPS에서 실제로 사용되는 표준</li>
<li>더 강력한 암호화 방식과 보안 구조 제공</li>
</ul>
<p>HTTPS 통신에서 이 인증서를 통해 서버의 <code>신원 인증</code>, <code>데이터의 암호화</code>, <code>데이터의 무결설 보장</code> 이 세 가지가 가능해진다.</p>
<h3 id="인증서는-왜-필요한가">인증서는 왜 필요한가?</h3>
<p>만약 인증서가 없다면 어떻게 될까?
-&gt; 사용자는 접속한 서버가 진짜인지 알 수 없다. </p>
<p>예를 들어, 브라우저에서 <code>https://www.naver.com</code>에 접속하면, 네이버 서버는 <strong>SSL/TLS 인증서</strong>를 브라우저에 보내준다.</p>
<p>이 인증서에는 <strong>“이 서버는 <a href="http://www.naver.com%EC%9D%98">www.naver.com의</a> 서버다”</strong>라는 정보와 이를 <code>신뢰할 수 있는 인증기관(CA)</code>이 확인했다는 서명이 들어 있다.</p>
<p>브라우저는 이 인증서를 검증한 뒤에야 통신을 시작한다. 그래서 사용자는 <strong>진짜 네이버 서버와 통신 중이라는 것을 보장</strong>받을 수 있다❕</p>
<h3 id="ca-certificate-authority란">CA (Certificate Authority)란?</h3>
<p>인증서를 발급하고 관리하는 <strong>신뢰 기관</strong>으로, </p>
<ul>
<li>서버가 해당 도메인의 실제 소유자인지 확인</li>
<li>확인이 끝나면 인증서를 발급</li>
<li>인증서에 전자 서명 추가
👆 같은 역할을 한다. </li>
</ul>
<p>그래서 CA가 서명한 인증서라면 브라우저는 자동으로 서버를 신뢰하게 된다!</p>
<h2 id="https는-어떻게-동작할까">HTTPS는 어떻게 동작할까?</h2>
<p>앞서 말했다시피 HTTPS는 SSL/TLS라는 보안 프로토콜을 사용하는데, 
<code>SSL</code>란 초기 암호화 프로토콜로 설명할 수 있다. 현재는 거의 사용하지 않는 프로토콜이다.
<code>TLS</code>는 SSL을 개선한 <strong>⌜최신 표준 보안 프로토콜⌟</strong>로, 실제로 우리가 쓰는 HTTPS는 TLS기반이다!</p>
<blockquote>
<p>브라우저가 서버에 접속 -&gt; 서버가 SSL/TLS 인증서 전달 -&gt; 브라우저가 인증서 신뢰 여부 확인 -&gt; 암호화된 통신 시작 🔐</p>
</blockquote>
<hr>
<h2 id="http-vs-https-한눈에-비교">HTTP vs HTTPS 한눈에 비교</h2>
<p><del>지피티가 말아주는</del>
<img src="https://velog.velcdn.com/images/dev-joohee/post/fe9141a6-2200-4659-98ee-5d4bdcfefe61/image.png" alt=""></p>
<hr>
<p>결론적으로, HTTP보다는 보안 + 사용자 신뢰 + 브라우저 정책까지 모두 고려하는 HTTPS를 사용하는 것이 좋다! </p>
<p>마무리.ㅋ
<img src="https://velog.velcdn.com/images/dev-joohee/post/0634600b-d2f8-4da3-ba92-236566b5a97a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹보안] 쿠키·세션·토큰 딱 정리해보자]]></title>
            <link>https://velog.io/@dev-joohee/%EC%9D%B8%EC%A6%9DAuth-%EA%B3%B5%EB%B6%80%ED%95%98%EB%8B%A4-%ED%97%B7%EA%B0%88%EB%A0%B8%EB%8D%98-%EC%BF%A0%ED%82%A4Cookie%EC%84%B8%EC%85%98Session%ED%86%A0%ED%81%B0Token-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@dev-joohee/%EC%9D%B8%EC%A6%9DAuth-%EA%B3%B5%EB%B6%80%ED%95%98%EB%8B%A4-%ED%97%B7%EA%B0%88%EB%A0%B8%EB%8D%98-%EC%BF%A0%ED%82%A4Cookie%EC%84%B8%EC%85%98Session%ED%86%A0%ED%81%B0Token-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 28 Jan 2026 09:53:52 GMT</pubDate>
            <description><![CDATA[<p>최근 새로운 프로젝트를 시작하며 인증(Auth)과 관련된 API 연동을 하는데 인증 관련 API 연동을 한 경험이 다수 있음에도 불구하고 여전히 헷갈리는 개념들을 이번에~ 한큐에~ 정리해보고자 한다.</p>
<h1 id="쿠키-vs-토큰-애초에-비교부터-잘못되었음">쿠키 vs 토큰? 애초에 비교부터 잘못되었음..!</h1>
<p>인증을 공부하다 보면 &quot;쿠키 vs 토큰&quot; 이라는 표현을 자주 보게 된다.
하지만 이 둘은 서로 대체 관계가 아니라, <strong>역할이 완전히 다르다❗️</strong></p>
<p>쿠키(Cookie)는 <strong>저장 방식</strong>이고, 토큰은 <strong>저장되는 데이터의 한 종류</strong>다.
그래서 쿠키 자체를 토큰과 비교하는 것부터가 개념적으로 맞지 않는다. <del>맙소사</del>
<img src="https://velog.velcdn.com/images/dev-joohee/post/14ad7c51-beaa-4e6f-8fab-1d145193f219/image.png" alt=""></p>
<h1 id="쿠키cookie란">쿠키(Cookie)란?</h1>
<p>쿠키는 <strong>서버가 브라우저에 저장하도록 지시할 수 있는 작은 데이터</strong>다.
쿠키의 목적은 간단하다.</p>
<blockquote>
<p>서버가 사용자를 기억하기 위함🧘</p>
</blockquote>
<h2 id="쿠키는-어떻게-동작할까">쿠키는 어떻게 동작할까?</h2>
<p>웹사이트에 처음 방문하면, 브라우저는 서버에 요청(Request)을 보낸다.
서버는 이에 대한 응답(Response)을 보내는데, 이 응답에는 다음과 같은 것들이 포함될 수 있다.</p>
<ul>
<li>HTML 페이지</li>
<li>JSON 데이터</li>
<li>브라우저에 저장하라고 지시하는 쿠키(Set-Cookie)
브라우저는 이 쿠키를 저장해 두었다가, 이후 <strong>같은 웹사이트에 다시 요청할 때마가 쿠키를 자동으로 함께 전송</strong>한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dev-joohee/post/67536226-72cd-407e-94dc-a5b79077b5be/image.png" alt=""></p>
<p>즉, 서버는 매 요청마다 &quot;아, 이 사용자는 예전에 이런 정보를 가지고 있었구나&quot;라고 판단할 수 있게 된다!</p>
<h2 id="쿠키는-도메인-기준으로-동작한다">쿠키는 도메인 기준으로 동작한다</h2>
<p>쿠키는 <strong>도메인 단위로 제한</strong>된다.
예를 들어, <code>youtube.com</code>이 발급한 쿠키는 <strong>youtube.com으로 요청할 때만 전송</strong>된다.
다른 사이트에서는 해당 쿠키에 접근하거나 전송할 수 없다.</p>
<h2 id="쿠키는-유효기간이-있다">쿠키는 유효기간이 있다</h2>
<p>쿠키는 <strong>서버가 정한 유효기간(Expires/Max-Age)</strong>에 따라 유지된다.</p>
<ul>
<li>유효기간이 지나면 자동으로 삭제됨</li>
<li>세션 쿠키의 경우 브라우저 종료 시 삭제되기도 함</li>
</ul>
<h2 id="쿠키는-인증-외에도-사용된다">쿠키는 인증 외에도 사용된다</h2>
<p>쿠키는 <strong>인증 정보만 저장하는 용도가 아니다!</strong></p>
<p>예를 들어 <code>웹사이트 언어 설정</code>, <code>다크 모드 여부</code>, <code>사용자 UI 설정</code> 등에도 사용이 되는데 그 중 <code>웹사이트 언어 설정</code>의 경우, 사용자가 웹사이트에서 언어를 변경하면 서버는 해당 언어 정보를 쿠키에 저장해 둘 수 있다. 
이후 사용자가 다시 방문하면, 브라우저는 쿠키를 요청과 함께 보내고 서버는 쿠키에 저장된 언어 설정을 기반으로 <strong>해당 언어의 페이지를 제공</strong>한다👏</p>
<hr>
<p>그런데 쿠키를 이해하다 보면 자연스럽게 이런 의문이 생긴다.(실제로 내가 궁금했던 점들이다..)</p>
<ul>
<li>서버는 왜 사용자를 기억하지 못할까?</li>
<li>로그인 상태는 어떻게 유지되는 걸까?</li>
<li>세션과 토큰은 쿠키랑 뭐가 다른 걸까?</li>
</ul>
<p>이 질문에 답하기 위해서는 <strong>HTTP의 특성</strong>부터 다시 짚고 가야 한다.</p>
<hr>
<h1 id="http는-왜-사용자를-기억하지-못할까">HTTP는 왜 사용자를 기억하지 못할까?</h1>
<p>HTTP는 <strong>stateless(무상태)</strong> 프로토콜이다.
즉, 서버는 이전 요청을 기억하지 않고 모든 요청은 완전히 독립적으로 처리된다</p>
<blockquote>
<p>서버 입장에서는 &quot;이 요청을 보낸 사용자가 방금 로그인한 사람인지&quot; 알 방법이 없다❗️</p>
</blockquote>
<p>그래서 등장한 개념이 바로 _사용자를 어떻게 기억할 것인가_이고, 그 해답이 <strong>세션(Session)과 토큰(token)</strong>이다.</p>
<hr>
<h2 id="쿠키는-기억을-전달하는-수단이다">쿠키는 &#39;기억을 전달하는 수단&#39;이다</h2>
<blockquote>
<p>쿠키 자체가 인증 방식은 아니다.</p>
</blockquote>
<p>이 포인트를 잘 기억해야 한다. 쿠키는 단지 <code>서버가 브라우저에 데이터를 저장</code>하게 하고, 이후 <code>요청마다 그 데이터를 자동으로 전달해주는 수단</code>이다. </p>
<p>이 쿠키를 이용해</p>
<ul>
<li>서버가 직접 사용자를 기억하면 -&gt; 세션(Session)</li>
<li>서버가 기억하지 않으면 -&gt; 토큰(Token)</li>
</ul>
<p>이렇게 방식이 나뉜다.</p>
<hr>
<h1 id="사용자를-기억하는-방법-①세션session">사용자를 기억하는 방법 ①세션(Session)</h1>
<p>세션 방식은 <strong>서버가 사용자의 상태를 직접 기억하는 방식</strong>이다.</p>
<h3 id="세션-로그인-흐름">세션 로그인 흐름</h3>
<ol>
<li>사용자가 아이디/비밀번호로 로그인 요청</li>
<li>서버가 인증에 성공하면 <code>Session ID</code> 생성</li>
<li>서버는<ul>
<li><code>Session DB</code>에 <code>Session ID &lt;-&gt; 사용자 정보</code> 저장</li>
<li><code>Session ID</code>를 <strong>쿠키에 담아 브라우저로 전달</strong></li>
</ul>
</li>
<li>이후 요청마다 브라우저는 쿠키(Session ID)를 자동 전송</li>
<li>서버는 Session ID로 DB를 조회해 사용자 확인</li>
</ol>
<blockquote>
<p>즉, 중요한 정보는 전부 서버에 있고, 브라우저는 <code>Session ID</code>만 들고 다닌다</p>
</blockquote>
<h2 id="세션-방식의-특징">세션 방식의 특징</h2>
<ul>
<li>서버가 로그인한 사용자의 상태를 모두 관리</li>
<li>특정 사용자 세션을 삭제해 강제 로그아웃 가능</li>
<li>인증 상태를 서버가 즉시 제어 가능</li>
</ul>
<p>🙋‍♀️ 그래서 계정 정지, 강제 로그아웃, 특정 사용자 차단 같은 기능이 중요한 서비스에 적합하다! 그냥 Session을 삭제해버리면 되기 때문이다...</p>
<h2 id="세션-방식의-한계">세션 방식의 한계</h2>
<ul>
<li>로그인한 사용자 수만큼 서버 자원을 사용해야 함</li>
<li>트래픽 증가 시 Session DB 부하</li>
<li>서버 확장 시 세션 공유 문제 발생</li>
</ul>
<p>그래서 실제 서비스에서는 세션 정보를 <code>Redis</code> 같은 *<code>인메모리DB</code>로 분리하여 관리하기도 한다.</p>
<p><span style="color: grey"> * 인메모리 DB란 데이터를 디스크가 아닌 주기억장치(RAM)에 저장하는 데이터베이스임</span></p>
<h3 id="쿠키가-없는-환경에서는">쿠키가 없는 환경에서는?</h3>
<p>세션 방식은 쿠키에 의존한다.
하지만 모바일 앱(IOS/Android) 같은 네이티브 환경에서는 쿠키 사용이 제한적이다.</p>
<p>이때 자연스럽게 등장하는 방식이 <strong><code>토큰(Token)</code></strong> 기반 인증이다.</p>
<hr>
<h1 id="사용자를-기억하는-방법-②토큰token">사용자를 기억하는 방법 ②토큰(Token)</h1>
<p>토큰은 <strong>서버가 발급한 임의의 String</strong>이다.</p>
<p>세션과 달리, 서버가 사용자 상태를 직접 저장하지 않고 <strong>토큰 자체를 인증 수단</strong>으로 사용한다.</p>
<h3 id="토큰기반-인증-흐름">토큰기반 인증 흐름</h3>
<ol>
<li>사용자가 로그인</li>
<li>서버가 토큰 발급</li>
<li>클라이언트가 토큰 저장 (쿠키, localStorage 등)</li>
<li>이후 요청마다 토큰을 함께 전송</li>
<li>서버는 토큰을 검증하고 요청 처리</li>
</ol>
<p>이 방식에서는 서버가 &quot;이 사용자가 누구인지&quot;를 기억하지 않는다.</p>
<h2 id="jwtjson-web-token는-왜-등장했을까">JWT(JSON Web Token)는 왜 등장했을까?</h2>
<p>JWT는 토큰의 한 종류로, 차이점은 <strong>토큰 안에 사용자 정보가 들어있다</strong>는 점이다.
JWT에는 보통 <code>사용자 ID</code>, <code>만료 시간</code>, <code>권한 정보</code>와 같은 정보가 들어 있고, 서명을 통해 위변조 여부를 검증한다.</p>
<h2 id="jwt의-특징">JWT의 특징</h2>
<ul>
<li>서버는 DB 조회 없이(!!) 토큰 검증만으로 인증 가능</li>
<li>서버가 사용자 상태를 저장하지 않아도 됨</li>
<li>완전히 <strong>stateless</strong>한 인증 구조</li>
</ul>
<p>그래서 서버 확장이 쉽고, 대규모 트래픽 환경에 유리하다는 장점이 있다.</p>
<h2 id="jwt의-한계">JWT의 한계</h2>
<p>그렇다면 JWT가 좋기만 한가?? 그건 아니다. 다음과 같은 한계를 가진다.</p>
<ul>
<li>토큰이 유출될 경우 만료전까지 탈취한 사람(?)이 사용 가능</li>
<li>특정 사용자를 즉시 로그아웃 시키는 등의 추가 기능 사용이 어려움</li>
<li>토큰 길이가 너무 김</li>
</ul>
<p>그래서 실무에서는 짧은 만료시간의 <code>AccessToken</code>, 긴 만료시간의 <code>RefreshToken</code>을 함께 사용하는 구조가 많다.
<del>내가 했던 모든 프로젝트에서도 대부분 이런 구조였음</del></p>
<hr>
<h3 id="다시-정리해보면">다시 정리해보면</h3>
<ul>
<li>쿠키(Cookie): 데이터를 저장하고 자동으로 전송하는 수단, 매개체 정도</li>
<li>세션(Session): 쿠키(SessionID)를 이용해 서버가 사용자를 기억</li>
<li>토큰(Token): 서버가 발급한 인증용 문자열(String)</li>
<li>JWT: 사용자 정보를 포함한 토큰(DB 조회 없이 인증 가능함)<blockquote>
<p>쿠키 -&gt; &quot;어떻게 전달할까&quot;
세션/토큰 -&gt; &quot;무엇을 기억할까&quot;</p>
</blockquote>
</li>
</ul>
<p>정도로 아<del>~</del>주 간단하게 정리할 수 있을 것 같다. 
쿠키를 단순히 &quot;브라우저 저장소&quot;로만 이해하면 세션과 토큰 구조가 계속 헷갈린다 💦</p>
<p>공부하다보니 HttpOnly, Secure, SameSite 등등.. 더 공부해야 할 게 늘어났지만 정리하고 나니 현재 내가 진행하고 있는 서버의 흐름을 이해하기가 훨씬 명확해진 것 같다..</p>
<p>다음 글은 더 공부하고 또 정리해야것다</p>
<p>.
.
.
.
.
Thanks to 노마드코더, chatGPT</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WebSocket] 웹소켓이란?]]></title>
            <link>https://velog.io/@dev-joohee/WebSocket-%EC%9B%B9%EC%86%8C%EC%BC%93%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/WebSocket-%EC%9B%B9%EC%86%8C%EC%BC%93%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Mon, 07 Apr 2025 15:47:42 GMT</pubDate>
            <description><![CDATA[<h2 id="📡-웹소켓websocket이란">📡 웹소켓(WebSocket)이란?</h2>
<p>웹소켓은 웹에서 클라이언트(브라우저)와 서버가 실시간으로 양방향 통신을 할 수 있게 해주는 프로토콜</p>
<p>일반 HTTP 통신과 다르게 한 번 연결되면 끊어지지 않고 계속 연결을 유지하면서 서로 자유롭게 데이터를 주고 받을 수 있다는 것이 가장 큰 특징.</p>
<h3 id="✅-왜-필요한가">✅ 왜 필요한가?</h3>
<ul>
<li>실시간 채팅</li>
<li>실시간 알림</li>
<li>주식 시세, 실시간 데이터 스트리밍</li>
<li>위치 추적 서비스</li>
</ul>
<h3 id="🔥-typescript에서-웹소켓-연결하는-기본-구조">🔥 TypeScript에서 웹소켓 연결하는 기본 구조</h3>
<pre><code class="language-typeScript">// 웹소켓 인스턴스 생성
const socket = new WebSocket(&#39;ws://서버주소:포트&#39;);

// 연결 성공 시
socket.addEventListener(&#39;open&#39;, (event: Event) =&gt; {
  console.log(&#39;웹소켓 연결 성공&#39;);
  socket.send(&#39;클라이언트에서 보낸 메시지&#39;);
});

// 메시지 수신 시
socket.addEventListener(&#39;message&#39;, (event: MessageEvent) =&gt; {
  console.log(&#39;서버로부터 받은 메시지:&#39;, event.data);
});

// 에러 발생 시
socket.addEventListener(&#39;error&#39;, (event: Event) =&gt; {
  console.error(&#39;웹소켓 에러:&#39;, event);
});

// 연결 종료 시
socket.addEventListener(&#39;close&#39;, (event: CloseEvent) =&gt; {
  console.log(&#39;웹소켓 연결 종료:&#39;, event.code, event.reason);
});
</code></pre>
<h3 id="✅-웹소켓-상태-확인">✅ 웹소켓 상태 확인</h3>
<pre><code class="language-typeScript">if (socket.readyState === WebSocket.OPEN) {
  socket.send(&#39;이미 연결되어 있음&#39;);
}
</code></pre>
<h3 id="✅-사용자-정의-타입으로-메시지-다루기">✅ 사용자 정의 타입으로 메시지 다루기</h3>
<pre><code class="language-typeScript">// 예: 서버로부터 오는 JSON 데이터를 파싱할 경우
socket.addEventListener(&#39;message&#39;, (event: MessageEvent) =&gt; {
  const data: { type: string; payload: any } = JSON.parse(event.data);

  switch (data.type) {
    case &#39;chat&#39;:
      console.log(&#39;채팅 메시지:&#39;, data.payload);
      break;
    case &#39;notification&#39;:
      console.log(&#39;알림:&#39;, data.payload);
      break;
    default:
      console.warn(&#39;알 수 없는 메시지 유형&#39;);
  }
});</code></pre>
<h4 id="🙋-정리">🙋 정리</h4>
<ul>
<li><code>open</code> : 연결 성공 시</li>
<li><code>message</code> : 서버로부터 메시지 수신 시</li>
<li><code>error</code> : 에러 발생 시</li>
<li><code>close</code> : 연결 종료 시</li>
</ul>
<hr>
<h3 id="✅-react--typescript에서-웹소켓-사용하는-경우">✅ React + TypeScript에서 웹소켓 사용하는 경우</h3>
<h4 id="1️⃣-웹소켓을-어디서-생성할까">1️⃣ 웹소켓을 어디서 생성할까?</h4>
<p>보통 <code>useEffect</code> 훅 안에서 생성하고, 컴포넌트가 언마운트될 때 닫아주는 패턴 사용</p>
<pre><code class="language-Typescript">import React, { useEffect, useRef } from &#39;react&#39;;

const ChatComponent: React.FC = () =&gt; {
  const socketRef = useRef&lt;WebSocket | null&gt;(null);

  useEffect(() =&gt; {
    // 웹소켓 연결
    socketRef.current = new WebSocket(&#39;ws://서버주소:포트&#39;);

    socketRef.current.onopen = (event: Event) =&gt; {
      console.log(&#39;웹소켓 연결됨&#39;);
      socketRef.current?.send(&#39;안녕 서버야!&#39;);
    };

    socketRef.current.onmessage = (event: MessageEvent) =&gt; {
      console.log(&#39;받은 메시지:&#39;, event.data);
    };

    socketRef.current.onerror = (event: Event) =&gt; {
      console.error(&#39;에러 발생:&#39;, event);
    };

    socketRef.current.onclose = (event: CloseEvent) =&gt; {
      console.log(&#39;연결 종료:&#39;, event.code, event.reason);
    };

    // 클린업
    return () =&gt; {
      socketRef.current?.close();
    };
  }, []);

  return &lt;div&gt;채팅 중입니다...&lt;/div&gt;;
};
</code></pre>
<h3 id="2️⃣-메시지-데이터-타입-처리">2️⃣ 메시지 데이터 타입 처리</h3>
<p>서버가 JSON으로 데이터를 보낼 경우, <strong>타입</strong>을 명시해서 파싱하면 좋음</p>
<pre><code class="language-Typescript">type ServerMessage = {
  type: &#39;chat&#39; | &#39;notification&#39;;
  payload: any;
};

socketRef.current.onmessage = (event: MessageEvent) =&gt; {
  const data: ServerMessage = JSON.parse(event.data);
  if (data.type === &#39;chat&#39;) {
    console.log(&#39;채팅 메시지:&#39;, data.payload);
  }
};
</code></pre>
<h3 id="➕-tip">➕ Tip</h3>
<ul>
<li><code>useRef</code>로 socket 인스턴스를 관리하면 다시 렌더링될 때도 인스턴스를 유지할 수 있음.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[VScode] Prettier 설정 및 적용해보자!]]></title>
            <link>https://velog.io/@dev-joohee/VScode-Prettier-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev-joohee/VScode-Prettier-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sat, 05 Apr 2025 16:07:57 GMT</pubDate>
            <description><![CDATA[<p>코드 스타일을 자동으로 일관되게 정리해 주는 <strong>prettier</strong> 를 설치하고 적용해보자!</p>
<p>Q. Prettier 를 쓰면 어떤 점이 좋나요?</p>
<p>A. 코드 포맷을 자동 정리해주고, 일관된 코드 스타일을 유지시켜 줍니다. 그래서 팀 프로젝트나 협업 시 코딩 스타일을 통일할 수 있어요@^^@</p>
<hr>
<p>1️⃣ Vscode의 Extension &#39;Prettier&#39;를 설치해줍니다</p>
<p><img src="https://velog.velcdn.com/images/dev-joohee/post/363c1a69-8450-4e5a-9d67-4a4950754009/image.png" alt=""></p>
<p>2️⃣ VScode 설정(settings)에 들어간다.
<img src="https://velog.velcdn.com/images/dev-joohee/post/66b7df09-8523-4e6d-8df4-304f75e5a411/image.png" alt=""></p>
<p>2️⃣-1. 검색창에 &#39;editor.format&#39;을 친다.
2️⃣-2. &quot;Editor: Format On Save&quot;을 체크 ✔️
<img src="https://velog.velcdn.com/images/dev-joohee/post/d08a1380-2c5a-41d9-a739-49e749bde4bb/image.png" alt=""></p>
<p>3️⃣-1. 검색창에 &#39;default formatter&#39; 을 친다.
3️⃣-2. Default Formatter 에서 &#39;Prettier&#39;를 선택!
<img src="https://velog.velcdn.com/images/dev-joohee/post/ddbea110-01c1-42c8-94ce-4317466b2b35/image.png" alt=""></p>
<p>4️⃣ 이제부터는 저장하면 prettier가 적용된다! (코드가 이쁘게.. 🫶)
<img src="https://velog.velcdn.com/images/dev-joohee/post/e29f8a79-79ab-4b55-a8a6-99661e920846/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useEffect란?]]></title>
            <link>https://velog.io/@dev-joohee/React-useEffect%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/React-useEffect%EB%9E%80</guid>
            <pubDate>Sat, 01 Mar 2025 15:09:36 GMT</pubDate>
            <description><![CDATA[<h2 id="🔥useeffect-완전-정복🔥">🔥<code>useEffect</code> 완전 정복!🔥</h2>
<p>React에서 <code>useEffect</code>는 <strong>컴포넌트의 생명주기</strong>를 다룰 때 사용하는 Hook임
예를 들어, <strong>컴포넌트가 렌더링 될 때 데이터 가져오기</strong>, <strong>DOM 업데이트</strong> 같은 부수효과(side effect)를 실행할 때 사용됨</p>
<h3 id="useeffect는-언제-쓰나요"><code>useEffect</code>는 언제 쓰나요?</h3>
<p>1️⃣ <strong>컴포넌트가 처음 렌더링</strong>될 때 실행 (<code>ex</code>API에서 데이터 가져오기)
2️⃣ <strong>특정 값이 변경</strong>될 때 실행 (<code>ex</code> state나 props가 변경될 때 반응)
3️⃣ <strong>컴포넌트가 사라질 때</strong> 정리(clean-up) 작업 수행 (<code>ex</code> 이벤트 리스너 제거, 타이머 제거)</p>
<h4 id="useeffect-기본-문법"><code>useEffect</code> 기본 문법</h4>
<pre><code class="language-javascript">import { useEffect } from &quot;react&quot;;

useEffect(() =&gt; {
  // 여기에 실행할 코드 작성
});</code></pre>
<p>✔️ 이렇게만 작성하면?
=&gt; 렌더링될 때마다 실행됨 (원하지 않는 불필요한 실행이 생길 수도 있음!)</p>
<h4 id="useeffect-실행-시점-컨트롤하기"><code>useEffect</code> 실행 시점 컨트롤하기</h4>
<p>1️⃣ 마운트(처음 렌더링) 시 한 번만 실행</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;컴포넌트가 처음 렌더링됨!&quot;);
}, []);</code></pre>
<p>✔️ <code>[]</code>(의존성 배열)이 비어 있으면 <strong>한 번만 실행됨</strong>
✔️ 컴포넌트가 <strong>처음 나타날 때만 실행</strong>하고, <strong>이 후에는 실행되지 않음</strong></p>
<p>2️⃣ 특정 값이 변경될 때 실행</p>
<pre><code class="language-javascript">useEffect(()=&gt;{
    console.log(`count 값이 변경됨:&#39;, ${count}`);
}, [count]);</code></pre>
<p>✔️ <code>count</code> 값이 변경될 때마다 <code>useEffect</code>가 실행됨
✔️ <code>count</code> 가 변경되지 않으면 실행되지 않음</p>
<p>3️⃣ 언마운트 시(컴포넌트가 사라질 때) 정리(clean-up)</p>
<pre><code class="language-javascript">import { useEffect } from &quot;react&quot;;

useEffect(() =&gt; {
  const interval = setInterval(() =&gt; {
    console.log(&quot;1초마다 실행 중...&quot;);
  }, 1000);

  return () =&gt; {
    clearInterval(interval);
    console.log(&quot;타이머가 제거됨!&quot;);
  };
}, []);</code></pre>
<p>✔️ <code>return</code> 안에 있는 함수는 <strong>컴포넌트가 사라질 때 실행됨</strong>
✔️ 주로 이벤트 리스너 제거, 타이머 정리, 웹소켓 연결 종료 등에 사용됨</p>
<hr>
<h4 id="실전-예제">실전 예제!</h4>
<p>1️⃣ API 데이터 가져오기 (처음 렌더링 시 한 번만 실행)</p>
<pre><code class="language-javascript">import { useEffect, useState } from &quot;react&quot;;

const App = () =&gt; {
  const [data, setData] = useState(null);

  useEffect(() =&gt; {
    fetch(&quot;https://jsonplaceholder.typicode.com/todos/1&quot;)
      .then((response) =&gt; response.json())
      .then((json) =&gt; setData(json));
  }, []);

  return &lt;div&gt;{data ? JSON.stringify(data) : &quot;로딩 중...&quot;}&lt;/div&gt;;
};</code></pre>
<p>2️⃣ 윈도우 크기 변경 감지 (특정 값 변경 시 실행)</p>
<pre><code class="language-javascript">import { useEffect, useState } from &quot;react&quot;;

const App = () =&gt; {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() =&gt; {
    const handleResize = () =&gt; setWidth(window.innerWidth);

    window.addEventListener(&quot;resize&quot;, handleResize);

    return () =&gt; {
      window.removeEventListener(&quot;resize&quot;, handleResize);
    };
  }, []);

  return &lt;div&gt;현재 창 너비: {width}px&lt;/div&gt;;
};</code></pre>
<p>✔️ <code>window.addEventListener</code> 추가
✔️ 컴포넌트가 사라질 때 <code>removeEventListener</code>로 정리(clean-up)</p>
<hr>
<blockquote>
<p>✅ 정리</p>
</blockquote>
<ul>
<li><code>useEffect(() =&gt; {...})</code> : 매 렌더링마다 실행</li>
<li><code>useEffect(() =&gt; {...}, [])</code> : 처음 한 번만 실행 (마운트 시)</li>
<li><code>useEffect(() =&gt; {...}, [변수])</code> : 특정 겂아 변경될 때 실행</li>
<li><code>useEffect(() =&gt; { return () =&gt; {...}}, [])</code> : 언마운트 시 정리 작업 수행</li>
</ul>
<p>‼️<code>useEffect</code> 사용 시 주의할 점</p>
<ol>
<li>의존성 배열을 정확하게 설정해야 함</li>
</ol>
<ul>
<li>의존성 배열을 실수로 빠뜨리면 원치 않는 반복 실행이 발생할 수 있음</li>
</ul>
<ol start="2">
<li>클린업 함수(return)를 잘 활용해야 함</li>
</ol>
<ul>
<li>이벤트 리스너, 타이머 등을 정리하지 않으면 메모리 누수 발생 가능</li>
</ul>
<ol start="3">
<li>불필요한 렌더링을 방지해야 함</li>
</ol>
<ul>
<li><code>useEffect</code> 내에서 상태(state)를 변경하면 무한 루프가 발생할 수 있음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useState란?]]></title>
            <link>https://velog.io/@dev-joohee/React-useState%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/React-useState%EB%9E%80</guid>
            <pubDate>Fri, 28 Feb 2025 16:14:39 GMT</pubDate>
            <description><![CDATA[<h3 id="usestate란">useState란?</h3>
<p><code>useState</code>는 React의 상태(state) 관리 함수로, 컴포넌트의 상태를 저장하고 변경할 수 있도록 도와주는 <strong>React Hook</strong>임.</p>
<h3 id="📌-usestate-의-기본-사용법">📌 <code>useState</code> 의 기본 사용법</h3>
<pre><code class="language-javascript">import { useState } from &quot;react&quot;;

const Counter = () =&gt; {
  // count 상태를 선언하고, 초기값을 0으로 설정
  const [count, setCount] = useState(0);

  return (
    &lt;div&gt;
      &lt;p&gt;현재 카운트: {count}&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;+1 증가&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default Counter;</code></pre>
<ol>
<li><code>useState(0)</code> 을 이용해서 <code>count</code> 상태 변수를 만들고, 초기값을 <code>0</code>으로 설정함</li>
<li><code>setCount</code> 함수를 이용해 <code>count</code> 값을 변경할 수 있음</li>
<li>버튼을 클릭하면 <code>setCount(count+1)</code> 이 실행되어 숫자가 1씩 증가함</li>
</ol>
<hr>
<h3 id="📌-usestate-상세-설명">📌 <code>useState</code> 상세 설명</h3>
<p>1️⃣ <strong><code>useState</code> 의 기본 형태</strong></p>
<pre><code class="language-javascript">const [state, setState] = useState(intialValue);</code></pre>
<ul>
<li><code>state</code>: 현재 상태 값을 저장하는 변수</li>
<li><code>setState</code>: 상태를 변경하는 함수</li>
<li><code>initialValue</code>: 상태의 초기값</li>
</ul>
<p><strong>예제 살펴보기</strong></p>
<ol>
<li>문자열 상태</li>
</ol>
<pre><code class="language-javascript">const  [name, setName] = useState(&quot;Wonbin&quot;);

setName(&quot;Park&quot;); // 상태 변경 -&gt; 화면 다시 렌더링 됨</code></pre>
<ol start="2">
<li>boolean 값 상태(true/false)<pre><code class="language-javascript">const [isVisible, setIsVisible] = useState(false);
</code></pre>
</li>
</ol>
<p>setIsVisible(true); // 상태 변경</p>
<pre><code>
**2️⃣ `useState` 에서 객체 사용하기**
```javascript
const [user, setUser] = useState({ name: &quot;Wonbin&quot;, age: 24});

const updateAge = () =&gt; {
    setUser({...user, age:user.age + 1}); // 기존 객체 복사 후 age만 변경
}</code></pre><blockquote>
<h3 id="span-stylecolorred주의할-점span"><strong><span style="color:red">주의할 점</span></strong></h3>
<p><code>setUser(user.age = 23);</code> 과 같은 형식으로는 해선 안됨!
React는 상태가 직접 변경되면 <strong>변경을 감지하지 못하므로</strong> 반드시 <code>setState</code>를 사용해주어야 함!</p>
</blockquote>
<p><strong>3️⃣ <code>useState</code>에서 배열 사용하기</strong></p>
<pre><code class="language-javascript">const [items, setItems] = useState([&quot;사과&quot;, &quot;바나나&quot;]);

const addItem = () =&gt; {
    setItems([...items, &quot;포도&quot;]); // 기존 배열을 복사힌 후 새로운 값 추가
}</code></pre>
<p>=&gt; 배열을 업데이트할 때는 <strong>기존 배열을 복사하고 새 값을 추가</strong>해야 함.
(React는 기존 상태와 새로운 상태를 비교하여 변경된 부분만 렌더링하기 때문임)</p>
<hr>
<h3 id="usestate에서-상태-변경하는-방법"><code>useState</code>에서 상태 변경하는 방법</h3>
<h4 id="기본적인-상태-변경">기본적인 상태 변경</h4>
<pre><code class="language-javascript">setCount(5); // count 값을 5로 변경</code></pre>
<h4 id="이전-상태를-기반으로-변경-함수형-업데이트">이전 상태를 기반으로 변경 (함수형 업데이트)</h4>
<pre><code class="language-javascript">setCount(prevCount =&gt; prevCount + 1);</code></pre>
<ul>
<li>이렇게 하면 최신 상태 값을 기반으로 안전하게 업데이트 할 수 있음.</li>
<li>여러 번 setCount(count+1)을 호출하면 한 번만 업데이트 될 수 있으므로, <strong>함수형 업데이트</strong>를 사용하면 좋음!</li>
</ul>
<pre><code class="language-javascript">setCount(prev =&gt; prev + 1);
setCount(prev =&gt; prev + 1);
setCount(prev =&gt; prev + 1);</code></pre>
<p>=&gt; 이렇게 하면 <code>count</code>값이 3씩 증가하게 됨</p>
<hr>
<h3 id="usestate-사용-시-주의할-점"><code>useState</code> 사용 시 주의할 점</h3>
<ol>
<li>상태를 직접 변경해서는 안됨!<pre><code class="language-javascript">const [user, setUser] = useState({ name: &quot;Wonbin&quot;, age: 24 });
</code></pre>
</li>
</ol>
<p>user.age = 24; // 다음과 같은 방식 ❌</p>
<pre><code>=&gt; 이렇게 하면 React가 변경을 하지 못해서 화면이 업데이트 되지 않음.
✅ 올바른 방법:
```javascript
setUser({...user, age: 23 });</code></pre><ol start="2">
<li>상태 변경은 비동기적으로 처리됨<pre><code class="language-javascript">console.log(count);
setCount(count + 1);
console.log(count); // 여전히 이전 값이 출력됨</code></pre>
=&gt; 상태가 바로 업데이트 되는 것이 아니라 <strong>비동기</strong>적으로 처리되므로 <code>setCount</code> 후 바로 <code>console.log(count)</code>를 하면 이전 값이 출력될 수 있음.</li>
</ol>
<p>✅ 올바른 방법:</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;count 값이 변경됨:&quot;, count);
}, [count]); // count 값이 변경될 때 실행됨</code></pre>
<p>=&gt; 상태 변경 후 실행되는 효과를 보고 싶다면 <code>useEffect</code> 사용</p>
<hr>
<h3 id="usestate-실전-예제"><code>useState</code> 실전 예제</h3>
<p><strong>1️⃣ 입력값을 관리하는 상태</strong></p>
<pre><code class="language-javascript">const InputBox = () =&gt; {
  const [text, setText] = useState(&quot;&quot;);

  return (
    &lt;div&gt;
      &lt;input
        type=&quot;text&quot;
        value={text}
        onChange={(e) =&gt; setText(e.target.value)}
      /&gt;
      &lt;p&gt;입력한 값: {text}&lt;/p&gt;
    &lt;/div&gt;
  );
};</code></pre>
<p>=&gt; 사용자가 입력한 값을 <code>text</code> 상태에 저장하고 화면에 반영</p>
<p><strong>2️⃣ 배열에서 데이터 추가하기</strong></p>
<pre><code class="language-javascript">import { useState } from &quot;react&quot;;

const TodoList = () =&gt; {
  const [todos, setTodos] = useState([&quot;공부하기&quot;, &quot;운동하기&quot;]);

  const addTodo = () =&gt; {
    setTodos([...todos, &quot;새로운 할 일&quot;]); // 기존 배열 복사 후 새로운 값 추가
  };

  return (
    &lt;div&gt;
      &lt;ul&gt;
        {todos.map((todo, index) =&gt; (
          &lt;li key={index}&gt;{todo}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
      &lt;button onClick={addTodo}&gt;할 일 추가&lt;/button&gt;
    &lt;/div&gt;
  );
};</code></pre>
<p>=&gt; <code>setTodos([...todos, &quot;새로운 할 일&quot;])</code>을 사용하여 기존 배열을 유지하면서 새로운 항목을 추가</p>
<hr>
<blockquote>
<p>‼️ <strong>useState</strong> 정리</p>
</blockquote>
<ul>
<li><code>useState</code> : React의 상태 관리 Hook</li>
<li>사용 방법: <code>const [state, setState] = useState(초기값)</code></li>
<li>상태 변경: <code>setState(새로운 값)</code></li>
<li>이전 값 기반 업데이트: <code>setState(prev =&gt; prev + 1)</code> </li>
<li>객체 업데이트: <code>setState({...state, 변경할 값})</code></li>
<li>배열 업데이트: <code>setState([...state, 새로운 값])</code></li>
</ul>
<p>✔️ <code>useState</code>는 React에서 가장 기본적이면서 중요한 Hook!
✔️ 상태를 직접 변경하지 말고 항상 <code>setState</code>를 사용해야 함
✔️ 상태 변경은 <strong>비동기적으로 처리됨</strong>을 항상 기억!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] API ]]></title>
            <link>https://velog.io/@dev-joohee/TypeScript-API</link>
            <guid>https://velog.io/@dev-joohee/TypeScript-API</guid>
            <pubDate>Fri, 18 Oct 2024 15:21:21 GMT</pubDate>
            <description><![CDATA[<h2 id="api란">API란?</h2>
<p><code>API(Application Programming Interface)</code> 란, 쉽게 말해서 <strong>컴퓨터들이 서로 대화할 수 있도록 도와주는 방법</strong> 이라고 볼 수 있음.</p>
<p>예를 들어,
<img src="https://velog.velcdn.com/images/dev-joohee/post/ab2d89ab-1d00-4f80-9899-8475f949e0a6/image.png" alt="">
피자 가게에서 피자를 주문할 때, 우리는 메뉴판을 보고 원하는 피자를 선택하고, 그 피자의 이름과 사이즈 등을 직원에게 말함. 그러면 직원은 우리가 말한 주문대로 피자를 만들어 줌. 여기서 API는 우리와 피자 가게 사이에서 서로 대화를 돕는 <code>메뉴판과 직원</code> 같은 역할을 함.</p>
<ul>
<li><strong>피자가게</strong>: 우리가 주문하고 싶은 정보나 서비스를 제공하는 곳 <span style="color:skyblue">(<code>ex</code> 인터넷의 어떤 서비스나 웹)</span></li>
<li><strong>주문서</strong>: 우리가 피자를 어떻게 만들지 알려주는 정보 <span style="color:skyblue">(API를 통해 우리가 요청하는 것)</span></li>
<li><strong>피자 완성</strong>: 주문서대로 만든 피자를 우리에게 전달하는 것 <span style="color:skyblue">(API가 우리에게 결과를 보내주는 것)</span></li>
</ul>
<hr>
<h3 id="rest-api란">REST API란?</h3>
<p>REST(Representational State Transfer) API는 클라이언트와 서버 간에 데이터를 주고 받기 위한 URL 규칙임.
하이퍼 미디어(링크)를 기반으로 특정 리소스나 데이터를 접근하기 위한 방식으로써 <code>URL</code>에 명시적으로 어떤 데이터를 담고 있는지 나타내야 함.</p>
<p>예를 들어, 사용자의 목록을 받아오는 URL은 다음과 같음</p>
<pre><code>http://domain.com/api/users
</code></pre><p>여기서 첫 번째 사용자 데이터는 다음과 같이 접근할 수 있음.</p>
<pre><code class="language-code">http://domain.com/api/users/1
</code></pre>
<hr>
<h3 id="api-함수-예시">API 함수 예시</h3>
<p><a href="https://jsonplaceholder.typicode.com/todos">https://jsonplaceholder.typicode.com/todos</a>
<img src="https://velog.velcdn.com/images/dev-joohee/post/0746d8df-6b81-4d4f-8e99-0311455fa4d0/image.png" alt=""></p>
<pre><code class="language-typescript">const apiUrl: string = &#39;https://jsonplaceholder.typicode.com/todos&#39;;

interface Todo { // API에서 반환하는 Todo 객체의 구조 정의. 해당 인터페이스는 각 할 일 항목이 다음 속성들을 가지고 있음을 명시함.
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}  

//TODO: 아래 API 함수의 타입을 정의해 보세요
async function fetchTodos(): Promise&lt;Todo[]&gt; { 
  const response = await fetch(apiUrl);
  const data = await response.json();
  return data;
}  

fetchTodo().then(todos =&gt; todos[0].id);
</code></pre>
<p>이 코드에서는 </p>
<ul>
<li><p><code>async</code> 키워드를 사용하여 함수가 비동기로 동작함을 나타내며, <code>await</code>로 비동기 작업을 처리함.</p>
</li>
<li><p><code>fetch(apiUrl)</code>을 사용하여 <code>apiUrl</code>에 GET 요청을 보내고, 응답을 받아서 <code>response</code> 변수에 저장함.</p>
</li>
<li><p><code>response.json()</code>은 응답 데이터를 JSON 형식으로 변환하여, 그 결과를 <code>data</code> 변수에 저장함.</p>
</li>
<li><p>함수는 <code>Promise&lt;Todo[]&gt;</code> 타입을 반환함. 즉, 이 함수는 할 일 목록(Todo)의 배열을 포함하는 프로미스를 반환하고, 반환되는 데이터는 <code>Todo</code> 인터페이스와 일치하는 구조로 되어 있음.</p>
</li>
<li><p><code>fetchTodos().then()</code> 함수가 비동기적으로 데이터를 가져오면 <code>.then()</code> 블록에서 할 일 목록을 처리할 수 있음.
<span style="color:gray"> 여기서는 첫 번째 할 일 항목의 <code>id</code> 값을 가져옴.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입단언(Type Assertion)이란?]]></title>
            <link>https://velog.io/@dev-joohee/Typescript-%ED%83%80%EC%9E%85%EB%8B%A8%EC%96%B8Type-Assertion%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/Typescript-%ED%83%80%EC%9E%85%EB%8B%A8%EC%96%B8Type-Assertion%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Fri, 11 Oct 2024 13:51:11 GMT</pubDate>
            <description><![CDATA[<h2 id="타입-단언">타입 단언</h2>
<p>타입스크립트에서의 타입 단언이란 개발자가 변수의 타입을 명시적으로 지정할 수 있는 방법.</p>
<p>Q.<span style="color:red"> 타입단언은 주로 어떨 때 사용될까요?</span>
A. <del><span style="color:gray"> 컴파일러가 타입을 정확하게 추론하지 못하거나, 개발자가 특정 상황에서 타입을 더 명확하게 전달할 때 사용됨.</span></del></p>
<pre><code class="language-typescript">const a = &#39;hi&#39; as any;</code></pre>
<p><code>as</code>를 통해 타입단언을 사용할 수 있음.</p>
<p>EX) </p>
<pre><code class="language-typescript">type Person = { name: string; age: number; }

const b = {} as Person;
b.name = &#39;Thor&#39;;</code></pre>
<p>위 코드에서 <code>Person</code>은 <code>{ name: string; age: number; }</code> 형태의 객체를 요구하고 있음.
<code>const b = {} as Person;</code>이 부분에서 실제로는 빈 객체 <code>{}</code>지만 <code>as Person</code>로 이 객체가 <code>Person</code> 타입임을 <strong>단언</strong>하는 과정임.</p>
<h4 id="이와같은-타입-단언은">이와같은 타입 단언은</h4>
<p>타입스크립트 컴파일러에게</p>
<blockquote>
<p>&quot;다음의 값은 이런 타입을 가진거야 그러니까 에러를 띄우지마!&quot;</p>
</blockquote>
<p>라고 말하는 것임.</p>
<hr>
<p>타입 단언 사용을 할 경우엔 오류가 난 코드를 컴파일 단계에서 발견하지 못하고 <code>런타임 단계</code>까지 가야 발견할 수가 있는데 이는 <strong>타입스크립트를 사용하는 장점을 무시한 셈이다...</strong>
(<code>any</code> 타입과 마찬가지로 <code>타입단언</code> 또한 남용해선 안됨)
<img src="https://velog.velcdn.com/images/dev-joohee/post/75b04735-391f-425f-8571-c43ee3875c7c/image.png" alt=""></p>
<hr>
<p><em>그럼에도 불구하고 <strong>타입단언을 사용하는 이유</strong>는 무엇인가?</em></p>
<h3 id="타입-단언의-효용성이-높은-시점은-언제인가">타입 단언의 효용성이 높은 시점은 언제인가?</h3>
<h4 id="1-html요소에-접근할-때">1. HTML요소에 접근할 때</h4>
<pre><code class="language-typescript">const Modal: React.FC = () =&gt; {
  return (
    &lt;&gt;
      {createPortal(
        &lt;Backdrop /&gt;,
        document.getElementById(&quot;backdrop&quot;) as HTMLDivElement
      )}
      {createPortal(
        &lt;ModalWrapper /&gt;,
        document.getElementById(&quot;overlay&quot;) as HTMLDivElement
      )}
    &lt;/&gt;
  );
};</code></pre>
<p>위의 코드는 react의 createPortal을 이용해서 Modal 컴포넌트를 만든 예시임.</p>
<p>index.html에 미리 <code>&lt;div id=backdrop&gt;</code>과 <code>&lt;div id=overlay/&gt;</code>를 만들어 두고 위와 같이 사용한다면 타입 단언을 사용해야 함.</p>
<h4 id="2-외부-데이터-소스와의-상호작용-시">2. 외부 데이터 소스와의 상호작용 시</h4>
<pre><code class="language-typescript">let data: any = fetchDataFromAPI();
let user = data as User;  // 데이터가 User 타입임을 단언</code></pre>
<p>API 호출이나 외부 라이브러리에서 데이터를 받아올 때 데이터의 타입이 <code>any</code>로 처리되는 경우가 많음. 이때 타입 단언을 사용해서 해당 데이터의 타입을 명확히 지정할 수 있음.</p>
<p>위의 코드에서는 <code>as User</code>를 사용하여 데이터가 <code>User</code> 타입임을 단언하였음</p>
<hr>
<h3 id="타입-단언으로-span-stylecolorred특정-타입을-강제할-수-없는span-상황은">타입 단언으로 <span style="color:red">특정 타입을 강제할 수 없는</span> 상황은?</h3>
<p>타입스크립트의 타입 단언은 <code>컴파일 타임</code>에만 유효하며 <code>런타임</code>에서 <strong>실제로 타입이 맞는지</strong> 검사하지 않음.</p>
<h4 id="1-호환되지-않는-타입을-강제하는-경우">1. 호환되지 않는 타입을 강제하는 경우</h4>
<pre><code class="language-typescript">let value: any = 42;
let str = value as string;  // 런타임 오류 가능</code></pre>
<p>위의 코드와 같이 숫자를 문자열로 단언하면 <code>컴파일러</code>는 통과시키지만 <code>런타임</code>에서 오류가 발생할 수 있음.</p>
<h4 id="2-null이나-defined에-대한-잘못된-단언">2. null이나 defined에 대한 잘못된 단언</h4>
<p><code>null</code> 인 값을 특정 객체 타입으로 단언하면, <code>런타임</code>에서 <strong>속성에 접근할 때</strong> 오류가 발생할 수 있음.</p>
<pre><code class="language-typescript">let someValue: any = null;
let obj = someValue as { name: string };  // null을 객체로 단언</code></pre>
<h4 id="3-dom-요소가-존재하지-않을-때">3. DOM 요소가 존재하지 않을 때</h4>
<p><strong>DOM 요소가 없는 경우</strong>에도 타입 단언을 하면, <code>속성</code> 접근 시 오류가 발생할 수 있음.</p>
<pre><code class="language-typescript">let inputElement = document.getElementById(&quot;nonExistent&quot;) as HTMLInputElement;
inputElement.value = &quot;Hello&quot;;  // 런타임 오류
</code></pre>
<p>위 코드에서는 <code>nonExistent</code>라는 id를 가진 HTML 요소가 없을 때, <code>null</code>을 입력 필드처럼 사용하려고 해서 오류가 발생할 수 있음.</p>
<h4 id="4-타입-변환과-혼동">4. 타입 변환과 혼동</h4>
<p><strong>타입단언은 값 자체를 변환하진 않음</strong>. 문자열을 숫자로 단언해도 <strong>실제 값은 변하지 않기 때문에</strong> <code>런타임 오류</code>가 발생할 수 있음.</p>
<pre><code class="language-typescript">let str: any = &quot;123&quot;;
let num = str as number;  // 변환되지 않음, 오류 가능</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 함수 파라미터 타입]]></title>
            <link>https://velog.io/@dev-joohee/TypeScript-%ED%95%A8%EC%88%98-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@dev-joohee/TypeScript-%ED%95%A8%EC%88%98-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%ED%83%80%EC%9E%85</guid>
            <pubDate>Wed, 09 Oct 2024 07:06:50 GMT</pubDate>
            <description><![CDATA[<h3 id="함수-타입-지정-₩수정하기">함수 타입 지정 <del>₩</del>수정하기</h3>
<blockquote>
<p><span style="color:red">타입스크립트에서 함수 파라미터에 타입을 지정하는 것은 함수의 인자에 대해 <strong>명확한 타입</strong>을 정의하고 <strong>타입 안정성</strong>을 보장함.
  또한 파라미터에 타입 지정을 통해 함수가 호출될 때 <strong>잘못된 타입의 인자가 전달되는 것을 컴파일 단계에서 방지할 수 있음</strong>.</span></p>
</blockquote>
<h4 id="1️⃣-기본적인-함수-파라미터-타입-지정">1️⃣ 기본적인 함수 파라미터 타입 지정</h4>
<p>: 각 함수의 파라미터에 <code>명시적</code>으로 타입을 지정하여 <strong>함수 호출 시 타입 오류를 방지</strong>함.</p>
<pre><code class="language-typescript">function greet(name: string): void {
  console.log(&quot;Hello, &quot; + name);
}

greet(&quot;Alice&quot;);  // 정상 작동
greet(42);       // 오류 발생: Argument of type &#39;number&#39; is not assignable to parameter of type &#39;string&#39;.
</code></pre>
<p>이 코드에서 <code>greet</code> 함수는 <code>name</code>이라는 <strong>문자열(string)</strong> 타입의 파라미터를 받음.
만약 <code>string</code>이 아닌 <code>number</code>나 다른 타입의 값을 전달하면 타입스크립트는 컴파일 시점에서 오류를 발생시킴.</p>
<hr>
<h4 id="2️⃣-여러-파라미터에-타입-지정">2️⃣ 여러 파라미터에 타입 지정</h4>
<p>: 여러 개의 파라미터가 있는 함수에서도 각각의 파라미터에 타입을 지정할 수 있음. 각 파라미터는 함수 정의에서 각자의 타입을 가져야 함.</p>
<pre><code class="language-typescript">function add(a: number, b: number): number {
  return a + b;
}

add(5, 3);     // 정상 작동
add(5, &quot;3&quot;);   // 오류 발생: Argument of type &#39;string&#39; is not assignable to parameter of type &#39;number&#39;.
</code></pre>
<p>이 함수는 두 개의 숫자 number 파라미터를 받고 그 합을 반환함.
만약 파라미터 중 하나라도 숫자가 아니면 <strong>컴파일 에러</strong>가 발생함.</p>
<hr>
<h4 id="3️⃣-선택적-파라미터">3️⃣ 선택적 파라미터</h4>
<p>: 타입스크립트에서는 특정 파라미터가 <strong>필수가 아니도록</strong> 할 수 있음. 이를 <code>선택적 파라미터(optional parameter)</code>라고 하며, 파라미터 뒤에 <code>물음표</code>(<code>?</code>)를 붙여서 선언할 수 있음. 선택적 파라미터는 전달되지 않을 경우 <code>undefined</code> 값을 가짐.</p>
<pre><code class="language-typescript">function greet(name: string, age?: number): void {
  if (age) {
    console.log(`Hello, ${name}. You are ${age} years old.`);
  } else {
    console.log(`Hello, ${name}.`);
  }
}

greet(&quot;Alice&quot;);        // &quot;Hello, Alice.&quot;
greet(&quot;Bob&quot;, 25);      // &quot;Hello, Bob. You are 25 years old.&quot;
</code></pre>
<hr>
<h4 id="4️⃣-기본값이-있는-파라미터default-parameter">4️⃣ 기본값이 있는 파라미터(Default Parameter)</h4>
<p>: 파라미터에 <code>기본값</code>을 설정할 수 있음. 설정한 기본값이 있는 파라미터는 함수가 호출될 때 <strong>해당 인자를 전달하지 않으면 기본값</strong> 이 사용됨.</p>
<pre><code class="language-typescript">function greet(name: string, greeting: string = &quot;Hello&quot;): void {
  console.log(greeting + &quot;, &quot; + name);
}

greet(&quot;Alice&quot;);         // &quot;Hello, Alice&quot;
greet(&quot;Bob&quot;, &quot;Hi&quot;);     // &quot;Hi, Bob&quot;
</code></pre>
<p><code>greeting</code> 파라미터는 기본값으로 <code>&quot;hello&quot;</code>를 가지며, 값이 전달되지 않으면 기본값이 사용됨.</p>
<hr>
<h4 id="5️⃣-rest-파라미터rest-parameter">5️⃣ Rest 파라미터(Rest Parameter)</h4>
<p>: <code>Rest</code> 파라미터를 사용하면 함수가 가변 인자를 받을 수 있음. Rest 파라미터는 <code>배열</code>로 수집되며, <code>타입</code> 또한 배열 타입으로 지정할 수 있음.</p>
<pre><code class="language-typescript">function sum(...numbers: number[]): number {
  return numbers.reduce((acc, num) =&gt; acc + num, 0);
}

console.log(sum(1, 2, 3));      // 6
console.log(sum(10, 20, 30));   // 60
</code></pre>
<p>위 코드에서 <code>sum</code> 함수는 가변 인자(<code>...number</code>)를 받아서 배열로 처리하며, 각 요소는 <code>number</code> 타입임. 여러 개의 숫자를 전달하면 그 합을 구하는 함수임.</p>
<p>&lt;&gt;function sum(num1, num2, ...numbers)</p>
<hr>
<h4 id="6️⃣-유니온-타입">6️⃣ 유니온 타입</h4>
<p>: 하나 이상의 타입을 허용함</p>
<h4 id="7️⃣-인터페이스를-통한-타입-지정">7️⃣ 인터페이스를 통한 타입 지정</h4>
<p>: 복잡한 객체 형태의 파라미터에 인터페이스 사용할 수 있음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 구조적 타이핑(Structural Typing)이란?]]></title>
            <link>https://velog.io/@dev-joohee/TypeScript-%EA%B5%AC%EC%A1%B0%EC%A0%81-%ED%83%80%EC%9D%B4%ED%95%91Structural-Typing%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/TypeScript-%EA%B5%AC%EC%A1%B0%EC%A0%81-%ED%83%80%EC%9D%B4%ED%95%91Structural-Typing%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Wed, 09 Oct 2024 06:13:13 GMT</pubDate>
            <description><![CDATA[<h2 id="구조적-타이핑이란">구조적 타이핑이란?</h2>
<h3 id="구조적-타이핑--구조적-타입-시스템structural-type-system">구조적 타이핑 = 구조적 타입 시스템(Structural Type System)</h3>
<p>객체나 데이터 타입을 정의할 때, 그 <strong>구조(멤버, 필드, 메서드 등)에 기반하여 타입을 결정</strong>하는 개념으로, 객체가 특정 타입을 따르기 위해서 <strong>명시적으로 그 타입을 선언할 필요가 없음.</strong>
대신 해당 객체가 그 타입의 구조를 충족하면 해당 타입으로 간주함.</p>
<p>≠ <strong>명목적 타입 시스템(Nominal Type System)</strong></p>
<p>구조적 타이핑에서는 객체의 이름보다는 객체가 갖고 있는 <code>속성</code>과 <code>메서드</code>가 중요함</p>
<pre><code class="language-typescript">interface Person {
    name: string;
    age: number;
}

let person = { name: &quot;Alice&quot;, age: 25 };
let anotherPerson: Person = person;  // 구조만 같으면 할당 가능
</code></pre>
<p>위의 예제에서는 <code>anotherPerson</code> 변수가 <code>Person</code> 타입으로 선언되었지만, <code>Person</code> 변수는 명시적으로 <code>Person</code> 타입으로 선언되지 않았음.
그러나 <code>person</code> 객체가 <code>Person</code> 타입의 구조를 만족하기 때문에 타입 추론에 의해 <code>anotherPerson</code> 변수에 할당될 수 있음.</p>
<p><strong>즉, 객체의 구조만 맞으면 해당 타입으로 간주됨</strong></p>
<p>Q.<span style="color:red">구조적 타이핑의 장점은?</span>
A. <del><span style="color:gray">객체가 특정 클래스를 명시적으로 상속받거나 구현하지 않더라도 구조만 맞으면 그 타입으로 사용할 수 있어서 유연하게 코드를 작성할 수 있다.
또한 간결한 코드 작성이 가능하다.</span></del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입별칭(Type Aliases)이란?]]></title>
            <link>https://velog.io/@dev-joohee/TypeScript-%ED%83%80%EC%9E%85%EB%B3%84%EC%B9%ADType-Aliases%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/TypeScript-%ED%83%80%EC%9E%85%EB%B3%84%EC%B9%ADType-Aliases%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 06 Oct 2024 11:25:18 GMT</pubDate>
            <description><![CDATA[<h2 id="타입별칭type-aliases이란">타입별칭(Type Aliases)이란?</h2>
<h4 id="특정-타입에-대해-새로운-이름을-붙여주는-기능">특정 타입에 대해 새로운 이름을 붙여주는 기능</h4>
<p>복잡한 타입을 더 간결하고 직관적인 이름으로 재사용할 수 있음. </p>
<pre><code class="language-typescript">type User = {
  name: string;
  age: number;
};

const user: User = {
  name: &quot;Alice&quot;,
  age: 30
};
</code></pre>
<p><code>type User</code>는 객체의 타입을 정의한 타입 별칭임. 이후 <code>User</code>를 타입으로 사용해 <code>user</code>라는 변수에 그 구조를 따르는 값을 할당함.</p>
<hr>
<h3 id="타입-확장">타입 확장(&amp;)</h3>
<p>기존 타입에 새로운 속성을 추가하거나 변형할 수 있음. 주로 <strong>인터섹션 타입</strong>을 사용해 타입을 확장함.</p>
<pre><code class="language-typescript">type Person = {
  name: string,
  age: number
}

type Student = Person &amp; { // 확장(상속)
  school: string
}

const jieun: Student = {
  name: &#39;jieun&#39;,
  age: 27,
  school: &#39;HY&#39;
}</code></pre>
<h4 id="❗️❗️-그러나-type은-span-stylecolorgray인터페이스와-달리span-선언적-확장이-불가능함">❗️❗️ 그러나 <strong>type</strong>은 <span style="color:gray"><del>인터페이스와 달리</del></span> 선언적 확장이 불가능함</h4>
<blockquote>
<p>타입 별칭은 그 자체로 완전한 정의이기 때문에 새로운 선언을 통해 확장하거나 병합할 수 없음.</p>
</blockquote>
<pre><code class="language-typescript">type User = {
  name: string;
};

// 새로운 속성을 추가하려고 시도해도 오류 발생
type User = {
  age: number;
}; // Error: Duplicate identifier &#39;User&#39;.
</code></pre>
<p>이처럼 타입 별칭은 한 번 정의되면 같은 이름으로 다시 선언해 확장할 수 없음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 인터페이스(interface)란?]]></title>
            <link>https://velog.io/@dev-joohee/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4interface%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4interface%EB%9E%80</guid>
            <pubDate>Sat, 05 Oct 2024 16:49:22 GMT</pubDate>
            <description><![CDATA[<h2 id="인터페이스interface란">인터페이스(interface)란?</h2>
<h4 id="객체-모양의-타입을-정의할-때-유용한-문법">객체 모양의 타입을 정의할 때 유용한 문법</h4>
<p>프레임워크(<span style="color:gray">리액트, 뷰 ... 등등</span>)에서는 주로 <code>API 응답</code>, <code>프롭스</code>, <code>변수</code>, <code>함수</code>를 정의할 때 자주 사용함.</p>
<pre><code class="language-typescript">interface Person {
  name: string;
  age: number;
}

const vision: Person= {
  name: &#39;비전&#39;,
  age: 3
};</code></pre>
<hr>
<h3 id="인터페이스-확장extends">인터페이스 확장(extends)</h3>
<p>js 클래스에서 상속을 할 때 *<em><code>extends</code> *</em>키워드를 사용하는데 인터페이스에서도 사용해주면 됨.</p>
<pre><code class="language-typescript">interface Person {
   name: string;
}

interface Developer extends Person {
   skill: string;
}

let fe: Developer = { name: &#39;josh&#39;, skill: &#39;TypeScript&#39; };</code></pre>
<h4 id="➕--인터페이스-확장은-여러-개-_extends_가-가능함">➕  인터페이스 확장은 여러 개 _<code>extends</code>_가 가능함.</h4>
<p>(참고로 클래스는 반드시 하나만 extends 할 수 있음)</p>
<pre><code class="language-typescript">interface Person {
   name: string;
   age: number;
}

interface Programmer {
   favoriteProgrammingLanguage: string;
}

interface Korean extends Person, Programmer { // 두개의 인터페이스를 받아 확장
   isLiveInSeoul: boolean;
}

const person: Korean = {
   name: &#39;홍길동&#39;,
   age: 33,
   favoriteProgrammingLanguage: &#39;kor&#39;,
   isLiveInSeoul: true,
};</code></pre>
<hr>
<h3 id="인터페이스-선언-병합-interface-declararion-merging">인터페이스 선언 병합 (interface Declararion Merging)</h3>
<p>동일한 이름을 가진 인터페이스를 여러 번 선언하면, TypeScript가 이를 <strong>자동으로 병합하여 하나의 인터페이스로 처리</strong>하는 기능</p>
<blockquote>
<p><strong>같은 이름을 가진 인터페이스</strong>를 <strong>여러 번 선언</strong>할 수 있으며, 
이 인터페이스들은 병합되어 하나의 확장된 형태로 동작.</p>
</blockquote>
<pre><code class="language-typescript">interface User {
  name: string;
}

interface User {
  age: number;
}

const user: User = {
  name: &quot;Alice&quot;,
  age: 30
};
</code></pre>
<p>위 코드에서 <code>User</code>라는 인터페이스를 두 번 선언했지만, TypeScript는 이를 <strong>병합</strong>하여 <code>name</code>과 <code>age</code> 속성을 모두 가지는 하나의 <code>User</code> 인터페이스로 처리함.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 객체타입 프롭스(props)란?]]></title>
            <link>https://velog.io/@dev-joohee/TypeScript-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%AD%EC%8A%A4Props</link>
            <guid>https://velog.io/@dev-joohee/TypeScript-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%AD%EC%8A%A4Props</guid>
            <pubDate>Sat, 05 Oct 2024 16:06:35 GMT</pubDate>
            <description><![CDATA[<h2 id="객체타입-프롭스props란">객체타입 프롭스(props)란?</h2>
<h3 id="컴포넌트가-전달받는-데이터가-객체-형태일-때의-프롭스를-의미">컴포넌트가 전달받는 데이터가 객체 형태일 때의 프롭스를 의미</h3>
<p>Q.<span style="color:red"> 객체 타입 프롭스를 사용하는 이유는? </span>
A. <del><span style="color:gray">여러 속성을 한 번에 전달하고 그 속성들을 개별적으로 사용할 수 있다는 장점이 있음. 특히 복잡한 데이터를 처리할 때 <strong>객체</strong>를 사용하여 여러 값을 <code>하나의 프롭스</code>로 전달하는 방식이 유용함.</span></del></p>
<pre><code class="language-typescript">interface UserProps {
  name: string;
  age: number;
}

function UserInfo(props: UserProps) {
  return (
    &lt;div&gt;
      &lt;p&gt;Name: {props.name}&lt;/p&gt;
      &lt;p&gt;Age: {props.age}&lt;/p&gt;
    &lt;/div&gt;
  );
}</code></pre>
<ul>
<li><code>UserProps</code>는 <code>name</code>과 <code>age</code>라는 두 가지 속성을 포함하는 객체 타입의 프롭스.</li>
<li><code>UserInfo</code> 컴포넌트는<code>name</code>과 <code>age</code>객체를 전달받아 내부에서 <strong><code>props.name</code></strong>과<strong><code>props.age</code></strong> 로 해당 값을 사용할 수 있음.</li>
</ul>
<hr>
<h3 id="➕-구조-분해-할당-가능"><strong>➕ 구조 분해 할당 가능</strong></h3>
<pre><code class="language-typescript">function UserInfo({ name, age }: UserProps) {
  return (
    &lt;div&gt;
      &lt;p&gt;Name: {name}&lt;/p&gt;
      &lt;p&gt;Age: {age}&lt;/p&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<ul>
<li>구조 분해 할당을 사용하면 <code>props</code> 객체에서 <code>name</code>과 <code>age</code>라는 속성을 바로 꺼내서 사용할 수 있음.
(원래는 <code>props.name</code>, <code>props.age</code>와 같이 사용)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입호환 (Type Compatibility)]]></title>
            <link>https://velog.io/@dev-joohee/TypeScript-%ED%83%80%EC%9E%85%ED%98%B8%ED%99%98-Type-Compatibility</link>
            <guid>https://velog.io/@dev-joohee/TypeScript-%ED%83%80%EC%9E%85%ED%98%B8%ED%99%98-Type-Compatibility</guid>
            <pubDate>Fri, 04 Oct 2024 13:50:27 GMT</pubDate>
            <description><![CDATA[<h1 id="타입호환-type-compatibility">타입호환 (Type Compatibility)</h1>
<h3 id="타입간의-호환-여부-변수에-특정-값을-할당할-수-있는지의-관점">타입간의 호환 여부, 변수에 특정 값을 할당할 수 있는지의 관점</h3>
<pre><code class="language-typescript">let a: number = 10;
let b: string = &#39;hi&#39;;
b=a; //에러 발생. 호환되지 않음</code></pre>
<p><span style="color:red">Q. 이 코드에서 에러가 발생하는데 그 이유는?</span>
  A.<del><span style="color:gray"><code>a</code>는 <code>number</code> 타입으로 선언되어 숫자 값인 <code>10</code>을 가지고 있는데, <code>b</code>는 <code>string</code> 타입으로 선언되어 문자값인 <code>&#39;hi&#39;</code>를 가지고 있다. 
  즉,<strong><code>a</code>변수와 <code>b</code>변수의 타입이 다르기 때문에</strong> 발생하는 에러이다.</span></del></p>
<hr>
<h2 id="유니온union-타입">유니온(Union) 타입</h2>
<p>자바스크립트의 <code>OR 연산자(||)</code>와 같이 <code>&#39;A&#39;</code> 이거나 <code>&#39;B&#39;</code>이다 라는 의미의 <strong>하나 이상의 타입이 될 수 있는 값</strong>을 표현함.</p>
<p>타입호환성 관점에서보면, 유니온 타입은 가각가의 타입 중 하나라도 맞으면 호환될 수 있음.</p>
<pre><code class="language-typescript">function logText(text: string | number) {
  // ...
}</code></pre>
<p>  <span style="color:red">Q. 유니온 타입을 사용해야 하는 이유는?</span>
  A. <del><span style="color:gray">유니온 타입을 사용하면 하나의 변수나 함수가 <strong>여러 타입</strong>을 받을 수 있음.
  예를 들어, <code>number</code>와 <code>string</code> 타입을 모두 처리해야 할 때 유니온 타입이 유용함.</span></del></p>
<pre><code class="language-typescript">  function getAge(age: number | string) {
   if(typeof age == ‘number’) {
    return age.toFixed(); // 정상 동작, age의 타입이 ‘number’로 추론되기 때문에 number 관련된 API를 쉽게 자동완성 할 수 있음
   }

   if(typeof age == &#39;string&#39;) {
     return age; // 문자열 그대로 반환
   }

   return new TypeError(&#39;age must be number of string&#39;); // 타입에러 코드</code></pre>
<p>이처럼 유니온 타입을 사용하면 타입스크립트의 장점을 살릴 수 있음.</p>
<hr>
<p>➕ <em><strong>타입에러 코드란?</strong></em>
JavaScript와 TypeScript에서 발생하는 오류 중 하나로, 값이나 연산이 올바른 데이터 타입이 아닐 때 발생하는 오류임.TypeScript에서는 주로 <code>타입 안정성을 보장</code>하기 위해 사용되기도 함.</p>
<p>주로 다음과 같은 경우에 사용됨</p>
<blockquote>
<ul>
<li>함수에 <strong>잘못된 타입의 인자가 전달</strong>되었을 때.</li>
</ul>
</blockquote>
<ul>
<li>객체에서 <strong>존재하지 않는 속성이나 메서드를 호출</strong>하려고 할 때.</li>
<li><code>null</code> 또는 <code>undefined</code>에 대해 프로퍼티에 접근하려고 할 때.</li>
</ul>
<pre><code class="language-typescript">  // number나 string이 아닌 타입이 들어온 경우
  return new TypeError(&#39;age must be number or string&#39;);
}</code></pre>
<p> <code>age</code>가 <code>number</code>또는 <code>string</code>일 때는 문제가 없지만, <code>boolean</code>, <code>object</code>, <code>undefined</code> 등의 타입이 잘못 들어왔을 때는 TypeError가 발생함.</p>
<p><span style="color:red">Q. 타입에러 코드를 사용하였을때의 장점은?</span>
A. <span style="color:gray"><del>함수가 올바른 타입의 값을 받지 못했을 경우에 경고할 수 있음.
명시적 오류 메시지를 통해 문제를 쉽게 추적하고 해결할 수 있게 도와줌.</del></span></p>
<hr>
<h2 id="인터섹션intersection-타입">인터섹션(intersection) 타입</h2>
<p>인터섹션 타입(Intersection Type)은 여러 타입을 모두 만족하는 하나의 타입을 의미함. 즉, 인터섹션 타입은 여러 타입의 <strong>모든 속성을 합친 타입</strong>임.</p>
<p>타입 호환성 관점에서 보면, 인터섹션 타입은 두 타입의 <strong>공통 부분을 만족해야만 호환</strong> 가능함.</p>
<pre><code class="language-typescript">  interface Person {
      name: string;
      age: number;
  }

  interface Developer {
      name: string;
      skill: number;
  }

  type Capt = Person &amp; Developer;</code></pre>
<p>  위의 예시 코드에서는 <code>Person</code> 인터페이스의 타입 정의와 <code>Developer</code> 인터페이스의 타입 정의를 <strong><code>&amp;</code> 연산자를 이용하여 합친 후 <code>Capt</code> 라는 타입에 할당</strong>하였음.</p>
<p>결과적으로 <code>Capt</code>의 타입은 아래와 같음.</p>
<pre><code class="language-typescript">{
  name: string;
  age: number;
  skill: string;
}</code></pre>
<p>이처럼 <code>&amp;</code> 연산자를 이용해 <strong>여러 개의 타입 정의를 하나로 합치는 방식</strong>을 인터섹션 타입을 정의할 수 있음.</p>
<hr>
<blockquote>
</blockquote>
<ul>
<li>유니온 타입은 <strong>여러 타입 중 하나</strong>를 허용하는 방식으로 <strong>타입 호환이 유연함</strong>.</li>
<li>인터섹션 타입은 <strong>여러 타입의 속성을 모두 가져야 하므로</strong> 더 엄격함.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 이벤트]]></title>
            <link>https://velog.io/@dev-joohee/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8</link>
            <guid>https://velog.io/@dev-joohee/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8</guid>
            <pubDate>Tue, 01 Oct 2024 06:38:13 GMT</pubDate>
            <description><![CDATA[<h4 id="제네릭generics">제네릭(Generics)</h4>
<p>: 재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징이 있음. 특히, 한 가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트를 생성하는 데 사용됨.
<strong>타입을 마치 함수의 파라미터처럼 사용하는 것, 타입을 넘겨 타입을 받겠다. (원하는 타입을 넘겨서 그대로 받겠다)</strong></p>
<pre><code>function getText(text) {
  return text;
}</code></pre><p>위 함수는 text 라는 파라미터에 값을 넘겨 받아 text를 반환해 줌.</p>
<pre><code>getText(&#39;hi&#39;); // &#39;hi&#39;
getText(10); // 10
getText(true); // true</code></pre><p>hi, 10, true 등 어떤 값이 들어가더라도 그대로 반환함.</p>
<pre><code>function getText&lt;T&gt;(text: T): T {
  return text;
}</code></pre><p>⬆️ 위  함수는 제네릭 기본 문법이 적용된 형태로, 함수를 호출할 때 아래와 같이 함수 안에서 사용할 타입을 넘겨줄 수 있음.</p>
<pre><code>getText&lt;string&gt;(&#39;hi&#39;);
getText&lt;number&gt;(10);
getText&lt;boolean&gt;(true);</code></pre><p>EX)</p>
<pre><code>interface Person {
    name: string;
    age:number;
}

interface Developer{
    name: string;
    age: string;
}

interface Admin{
    name: string;
    age: boolean;
}

const josh:Developer={
    name:&#39;josh&#39;,
    age:&#39;100&#39;
}</code></pre><p><strong><em>age</em></strong> 의 타입이 변경될 때마다 계속 다른 타입을 정의 해 나가야 하는 번거로움이 발생함.</p>
<p>⬇️</p>
<pre><code>// interface Person {
//     name: string;
//     age:number;
// }

// interface Developer{
//     name: string;
//     age: string;
// }

// interface Admin{
//     name: string;
//     age: boolean;
// }

interface Anyone&lt;T&gt; {
  name: string;
  age: T;
}

const josh: Anyone&lt;boolean&gt; = {
  name: &quot;josh&quot;,
  age: false,
};
</code></pre><p><strong>제네릭의 사용으로 더 효율적으로 코드를 사용할 수 있음.</strong></p>
<h3 id="리액트-인풋-이벤트-핸들러-코드">리액트 인풋 이벤트 핸들러 코드</h3>
<pre><code class="language-typescript">import {ChangeEvent, MouseEvent, useState} from &#39;react&#39;;


function ButtonHandler(){
   function showAlert(event:MouseEvent){ //onClick이벤트에 대한 핸들러 showAlert를 정의함.
    console.log(event); //event 객체를 콘솔에 출력함.
   }

return &lt;button onClick={showAlert}&gt;show&lt;/button&gt;;
};

function InputHandler(){
    const [todo, setTodo]=useState&lt;string&gt;(&#39;&#39;); //string은 굳이 안 넣어도 됨. 
    function updateTodo(event: ChangeEvent&lt;HTMLInputElement&gt;){
        setTodo(event.target.value);
    }
    return &lt;input type=&#39;text&#39; value={todo} onChange={updateTodo}/&gt;; //ChangeEvent를 통해 onchange의 이벤트 핸들러의 파라미터를 정의할 수 있음.
}

export {ButtonHandler, InputHandler};</code></pre>
<p>const [todo, setTodo]=useState<string>(&#39;&#39;); 에서 <string>이 없어도 되는 이유는 타입스크립트의 <em><strong>타입추론</strong></em> 기능 때문임.</p>
<ul>
<li>변수가 어떤 타입인지 명시적으로 지정하지 않아도, 할당된 값을 보고 타입을 자동으로 추론할 수 있음</li>
<li>이 코드에서 useState에 빈 문자열(&#39;&#39;)을 초기값으로 전달했기 때문에 todo의 타입은 <strong>자동으로 string</strong>으로 지정됨</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[타입 정의 방법]]></title>
            <link>https://velog.io/@dev-joohee/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%ED%83%80%EC%9E%85-%EC%A0%95%EC%9D%98-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@dev-joohee/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%ED%83%80%EC%9E%85-%EC%A0%95%EC%9D%98-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 27 Sep 2024 08:44:58 GMT</pubDate>
            <description><![CDATA[<h1 id="type-script-문법">Type Script 문법</h1>
<h2 id="함수의-타입-정의">함수의 타입 정의</h2>
<pre><code>function sum(a: number, b: number) : number{
    return a+b;
}</code></pre><ul>
<li>함수 선언: sum이라는 이름의 함수를 정의하고 있.</li>
<li>매개변수 타입:</li>
<li>이 함수는 숫자 두 개를 입력받는 코드로 <em><strong>a: number</strong>_와 _<strong>b: number:</strong></em> 두 개의 매개변수 a와 b는 모두 숫자(number) 타입으로 명시되어 있음. </li>
<li>반환 타입:</li>
<li><em><strong>: number</strong></em> 이 부분은 함수의 반환값이 숫자 타입이어야 한다는 것을 나타냄.</li>
<li><em><strong>return a + b</strong></em>: 두 매개변수 a와 b를 더한 값을 반환함. 이 연산 결과도 숫자이므로 함수의 반환 타입 조건을 만족함.</li>
</ul>
<h3 id="알아야-하는-타입스크립트-개념">알아야 하는 타입스크립트 개념</h3>
<ul>
<li>함수의 타입 정의 방법</li>
<li>타입 추론</li>
<li>함수의 파라미터 타입 정의</li>
<li>함수의 반환 타입 정의
  <strong>tip</strong> 타입표기 - 타입을 정의하는 방식: number:string</li>
</ul>
<h2 id="타입-스크립트-기본타입">타입 스크립트 기본타입</h2>
<ul>
<li><p>문자열(String): 자바스크립트 변수의 타입이 문자열인 경우</p>
<pre><code>let str: string = &#39;hi&#39;;</code></pre><p>: 를 이용해서 자바스크립트 코드에 타입을 정의하는 방식을 <strong><em>타입 표기</em></strong>라고 함.</p>
</li>
<li><p>숫자(number)</p>
<pre><code>let num: number = 10;</code></pre></li>
<li><p>진위(boolean)</p>
<pre><code>let isLoggedIn: boolean = false;</code></pre></li>
<li><p><em><strong>객체(object)</strong></em> : interface, class의 상위타입. 타입을 object로 정의하면, any 타입 처럼 모든 타입의 값을 정의할 수 있음</p>
</li>
</ul>
<pre><code>let obj: object = {name: &#39;NAME&#39;, age:29};
  obj={A: &#39;A&#39;, B: &#39;B&#39;};</code></pre><p>  ❗️객체를 object 타입으로 정의하는 경우 타입스크립트를 사용한 목적이 애매해질 수 있음.
  (타입스크립트는 타입 검사에 엄격한 편임)</p>
<ul>
<li>interface로 구현</li>
</ul>
<pre><code class="language-typescript">          interface IUser {
            name: string,
            age : number
          }

          let obj: IUser = { name: &#39;NAME&#39;, age: 29 };</code></pre>
<ul>
<li>type으로 구현</li>
</ul>
<pre><code class="language-typescript">          type UserType = {
            name: string,
            age : number
          }

          let obj: UserType = { name: &#39;NAME&#39;, age: 29 };</code></pre>
<hr>
<ul>
<li>배열 (array)</li>
</ul>
<pre><code>let arr: number[] = [1,2,3];</code></pre><pre><code>// 제네릭 사용
  let arr: Array&lt;number&gt; = [1,2,3];</code></pre><ul>
<li>튜플(tuple): 튜플은 배열의 길이가 고정되고 각 요소의 타입이 지정되어 있는 배열 형식</li>
</ul>
<pre><code>let arr: [string, number] = [&#39;hi&#39;, 10];</code></pre><p>만약에 정의하지 않은 타입, 인덱스로 접근할 경우 오류 남.</p>
<pre><code>arr[1].concat(&#39;!&#39;); // Error, &#39;number&#39; does not have &#39;concat&#39;
arr[5] = &#39;hello&#39;; // Error, Property &#39;5&#39; does not exist on type &#39;[string, number]&#39;</code></pre><ul>
<li>이넘(enum): 흔하게 쓰이는 타입으로 특정 값(상수)들의 집합을 의미하며 열거형 타입을 정의하는 데 사용됨. 이넘은 특정 값들의 집합을 이름으로 관리하고, 이러한 값을 논리적으로 그룹화할 수 있게 해줌.</li>
</ul>
<pre><code>enum Avengers { 
  Capt, 
  IronMan, 
  Thor 
}

let hero: Avengers = Avengers.Capt;</code></pre><p>❗️ enum은 인덱스 번호로도 접근가능함.</p>
<pre><code>enum Avengers { 
  Capt, 
  IronMan, 
  Thor 
}

let hero: Avengers = Avengers[0];</code></pre><ul>
<li>any: 특정 데이터의 타입을 잘 모르거나 자바스크립트 프로젝트에 타입스크립트를 점진적으로 적용할 때 사용하면 좋은 타입임. 단어 의미 그대로 모든 타입에 대해서 허용한다는 의미를 갖고 있음.
그러나 any 타입을 많이 사용하면 사용할수록 타입스크립트의 장점이 사라질 수 있음.</li>
</ul>
<pre><code>let str: any = &#39;hi&#39;;
let num: any = 10;
let arr: any = [&#39;a&#39;, 2, true];</code></pre><ul>
<li>void: 반환 값이 없는 함수의 반환타입. return이 없거나 return이 있더라도 반환하는 값이 없으면 함수의 반환 타입을 void로 지정함.</li>
</ul>
<pre><code>function printSomething(): void {
  console.log(&#39;sth&#39;);
}

function returnNothing(): void {
  return;
}</code></pre><ul>
<li>never: 절대 발생하지 않는 값을 의미하는 타입임. 함수가 반복문이나 에러 핸들링으로 인해 함수의 끝에 절대 도달하지 않는 경우에 never 타입을 사용할 수 있음</li>
</ul>
<pre><code>// 이 함수는 절대 함수의 끝까지 실행되지 않는다는 의미
function loopForever(): never {
  while (true) {
    // ..
  }
}

function neverEnd(): never {
  throw new Error(&#39;unexpected&#39;);
}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[타입스크립트(TypeScript)란?]]></title>
            <link>https://velog.io/@dev-joohee/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8TypeScript%EB%9E%80</link>
            <guid>https://velog.io/@dev-joohee/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8TypeScript%EB%9E%80</guid>
            <pubDate>Sun, 22 Sep 2024 13:50:51 GMT</pubDate>
            <description><![CDATA[<h4 id="자바스크립트에-타입을-부여한-언어"><em>자바스크립트에 &quot;타입&quot;을 부여한 언어</em></h4>
<pre><code>// TypeScript
const message: string = &#39;hi&#39;;

function sum(a: number, b: number): number {
    return a+b;
}</code></pre><p>a: number와 b: number: 두 개의 매개변수 a와 b는 모두 숫자(number) 타입으로 명시되어있음. 
즉, 이 함수는 숫자 두 개를 입력받아야함.
<strong><em>: number</em></strong> 부분은 함수의 반환값이 숫자 타입이어야 한다는 것을 나타냄.
return a + b: 두 매개변수 a와 b를 더한 값을 반환함. 이 연산 결과도 숫자이므로 함수의 반환 타입 조건을 만족함.</p>
<h2 id="타입스크립트를-사용하는-이유"><em>타입스크립트를 사용하는 이유?</em></h2>
<ol>
<li>사용자 경험: 실행 시점(컴파일 시점)의 에러를 어느정도 미리 잡아줌</li>
<li>개발자 경험: 코드 자동 완성, 코드 역할에 대한 정보 제공 등</li>
</ol>
<h3 id="사용자-경험_-에러의-사전-방지">사용자 경험_ 에러의 사전 방지</h3>
<pre><code>// @ts-check
/**
@param {number} a
@param {number} b
@returns
*/

function sum (a,b){
    return a+b;
}
sum (10, &#39;20&#39;) // &#39;20&#39; 문자열은 number에 해당하지 않음</code></pre><p>이러한 이유로 코드레벨에서 에러 사전 방지가 가능하다는 장점이 있음
=&gt; 에러 해결 시 문제 없이 잘 작동함!</p>
<p>.js 파일을 .ts 파일로 변환한다면?</p>
<pre><code>function sum (a: number, b: number){
    return a+b;
}
sum (10, &#39;20&#39;) // 잘못된 부분을 바로 파악할 수 있음</code></pre><h3 id="개발자-경험-코드-자동-완성-코드-역할에-대한-정보-제공-등">개발자 경험: 코드 자동 완성, 코드 역할에 대한 정보 제공 등</h3>
<ul>
<li>코드를 작성할 때 개발 툴의 기능을 최대로 활용할 수 있음.<pre><code>  - 타입이 지정되어 있기 때문에 Vscode에서 해당 타입에 대한 API를 미리보기로 띄워줄 수 있고, tab으로 빠르고 정확하게 작성할 수 있음.</code></pre></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>