<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>iamaiden</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 27 Jun 2023 03:09:37 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>iamaiden</title>
            <url>https://velog.velcdn.com/images/s_sangs/profile/a40c7148-408b-44e8-8a88-f7b5201e6e54/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. iamaiden. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/s_sangs" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[CSS 가상 클래스와 가상 요소]]></title>
            <link>https://velog.io/@s_sangs/CSS-%EA%B0%80%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%80%EC%83%81-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@s_sangs/CSS-%EA%B0%80%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%80%EC%83%81-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Tue, 27 Jun 2023 03:09:37 GMT</pubDate>
            <description><![CDATA[<h2 id="가상-요소">가상 요소</h2>
<p>요소의 특정한 부분에 CSS 속성을 적용할 수 있도록 선택자에 추가하는 키워드입니다.
요소에 CSS 속성을 적용하는 것과 같은 방법으로 다양한 CSS 속성을 적용할 수 있기 때문에 하나의 하위 요소처럼 사용할 수 있어서 가상 요소라고 합니다.</p>
<h3 id="가상-요소-리스트">가상 요소 리스트</h3>
<ul>
<li><code>::before</code>: 요소 내용 앞쪽에 새 컨텐츠를 추가합니다.</li>
<li><code>::after</code>: 요소 내용 끝에 새 컨텐츠를 추가합니다.</li>
<li><code>::selection</code>: 마우스 드래그로 선택한 텍스트 컨텐츠 영역을 선택합니다.</li>
<li><code>::marker</code>: 목록 요소(<code>li</code>) 앞에 붙는 마커를 선택합니다.</li>
<li><code>::first-letter</code>: 현재 웹 브라우저에 보이는 상태를 기준으로 요소의 텍스트 컨텐츠 첫 글자를 선택합니다.</li>
<li><code>::first-line</code>: 현재 웹 브라우저에 보이는 상태를 기준으로 요소의 텍스트 컨텐츠 첫 줄 내용을 선택합니다.</li>
</ul>
<p><code>::before</code>, <code>::after</code>만 새 컨텐츠를 추가하는 가상 요소이고, 나머지는 콘텐츠의 특정 영역을 선택하는 가상 요소입니다.</p>
<h3 id="가상-요소-작성-방법">가상 요소 작성 방법</h3>
<p>가상 요소는 앞에 콜론(<code>:</code>)을 2개 붙여서 표기합니다.</p>
<p>가상 클래스는 콜론을 1개 붙여서 표기합니다. CSS1, CSS2 때는 가상 요소도 콜론 1개로만 표시했었는데 CSS3에 오면서 가상 클래스와 가상 요소를 구분하기 위해서 콜론을 2개 붙여서 표기하기 시작했습니다.</p>
<p><code>:before</code>로 작성해도 가상 요소가 정상적으로 작동하는 이유는 웹 브라우저가 콜론 1개와 2개의 표기를 모두 지원하기 때문입니다.
그래도 가상 요소는 콜론을 2개 붙이는 것이 CSS3의 표준 표기 방법입니다.</p>
<pre><code class="language-css">span::before {
    content: &quot;&quot;;
    width: 120px;
}</code></pre>
<p>위처럼 가상 요소는 선택된 요소에 의존적인 키워드입니다.</p>
<p><strong>그렇다면 가상 클래스는 무엇일까요? 🤔</strong></p>
<h2 id="가상-클래스">가상 클래스</h2>
<p>사용자가 요소에 마우스 포인터를 올리거나 클릭하는 등 특정 이벤트마다 스타일을 적용할 수 있도록 선택자에 추가하는 키워드입니다.</p>
<p>개인적인 경험으로는 가상 요소보다는 가상 클래스를 더 많이 사용하는 것 같습니다.
특정 부분에 CSS 속성을 정하는 가상 요소와 달리 해당 요소의 특정 이벤트 시점에 스타일을 적용하는 것이 가상 요소와 가상 클래스의 가장 큰 차이점입니다.</p>
<h3 id="대표적인-가상-클래스-리스트">대표적인 가상 클래스 리스트</h3>
<ul>
<li><code>:link</code> - 방문한 적이 없는 링크</li>
<li><code>:visited</code> - 방문한 적이 있는 링크</li>
<li><code>:hover</code> - 마우스를 롤오버 했을 때</li>
<li><code>:active</code> - 마우스를 클릭 했을 때</li>
<li><code>:focus</code> - 포커스 되었을 때 (input 태그 등)</li>
<li><code>:first</code> - 첫번째 요소</li>
<li><code>:last</code> - 마지막 요소</li>
<li><code>:first-child</code> - 첫번째 자식</li>
<li><code>:last-child</code> - 마지막 자식</li>
<li><code>:nth-child(2n+1)</code> - 홀수 번째 자식</li>
</ul>
<p>가상 클래스를 사용하면 문서 트리 콘텐츠 뿐만 아니라 탐색기 히스토리(<code>:visited</code> 등), 콘텐츠의 상태, 마우스의 위치와 같은 외부 인자와 관련된 경우에도 스타일을 적용할 수 있습니다.</p>
<h3 id="가상-클래스-작성-방법">가상 클래스 작성 방법</h3>
<p>가상 클래스는 앞에 콜론(<code>:</code>)을 1개 붙여서 표기합니다.</p>
<pre><code class="language-css">button:hover {
  color: blue;
}</code></pre>
<h2 id="정리">정리</h2>
<p>기본에 충실하자.. 😎</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://blogpack.tistory.com/1025">https://blogpack.tistory.com/1025</a></li>
<li><a href="https://blueshare.tistory.com/405">https://blueshare.tistory.com/405</a></li>
<li><a href="https://ofcourse.kr/css-course/%EA%B0%80%EC%9E%A5-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%84%A0%ED%83%9D%EC%9E%90">https://ofcourse.kr/css-course/가장-클래스-선택자</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Promise에 대해서]]></title>
            <link>https://velog.io/@s_sangs/Promise%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</link>
            <guid>https://velog.io/@s_sangs/Promise%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</guid>
            <pubDate>Sun, 18 Jun 2023 09:54:14 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>오늘은 <code>Promise</code>에 대해서 이야기를 나눠보려고 합니다.</p>
<p>요즘 들어서 기본 개념이 매우매우 부족하다는 생각을 하고 있습니다.. 🤦‍♂️
사실 <code>Promise</code>에 대해서 공부하려고 하는 것도.. <code>axios</code> 라이브러리에 대해서 찾아보다가.. 이해가 잘 되지 않아서.. 찾아보게 되었습니다..</p>
<p>이러면서.. <code>react-query</code>와 같은 라이브러리를 사용하겠다는 제 자신이 조금 부끄러워집니다.. 💩
그래도 이렇게 하나씩 배워가는거 아니겠나..! 라는 생각으로 정리해보려고 합니다.</p>
<h2 id="promise"><code>Promise</code></h2>
<ul>
<li>자바스크립트 안에 내장되어 있는 객체(<code>Object</code>)</li>
<li>비동기 동작을 위한 객체(<code>Object</code>)</li>
<li><code>state</code>와 <code>Producer vs Consumer</code> 2가지의 포인트를 가지고 개념을 이해하는 것이 좋다</li>
</ul>
<h2 id="promise-생성"><code>Promise 생성</code></h2>
<pre><code class="language-js">const promise = new Promise((resolve, reject) =&gt; {
    ... // executor
})</code></pre>
<p><code>Promise</code>는 위와 같은 문법으로 생성할 수 있습니다.</p>
<p><code>new Promise()</code> 에 전달되는 함수는 <code>executor</code>라는 이름을 가지고 있는데, <code>(resolve, reject) =&gt; {}</code>와 같은 형태를 가지고 있습니다.
<code>executor</code>함수는  <code>new Promise</code>가 생성될 때 자동으로 실행됩니다.</p>
<h3 id="executor의-인수"><code>executor의 인수</code></h3>
<p><code>executor</code>는 <code>resolve</code>, <code>reject</code> 2가지 인수를 받을 수 있습니다.
<code>resolve</code>와 <code>reject</code>는 자바스크립트에서 자체적으로 제공하는 콜백 함수입니다.
따로 선언할 필요 없이 <code>executor</code> 함수 안에 작성만 해주면 됩니다.</p>
<p>대신 <code>executor</code>에서는 결과를 얻는 시점과 상관없이 상황에 따라 <code>resolve</code>와 <code>reject</code> 콜백 함수 중 하나를 반드시 호출해야 합니다.
왜냐하면, <code>executor</code>는 생성과 동시에 실행하게 되는데 <code>executor</code> 내부에서 로직을 처리하게 됩니다.
처리가 끝나면 바로 <code>resolve</code> 혹은 <code>reject</code> 콜백 함수를 호출하게 됩니다.</p>
<h3 id="resolve-reject"><code>resolve, reject</code></h3>
<ul>
<li><code>executor</code>의 처리 성공 여부에 따라 실행되는 콜백함수</li>
<li><code>resolve(value)</code>: 작업을 성공한 경우 결과(<code>value</code>)와 함께 호출</li>
<li><code>reject(error)</code>: 에러 발생 시 에러 객체를 나타내는 <code>error</code>와 함께 호출</li>
</ul>
<h2 id="producer"><code>Producer</code></h2>
<ul>
<li><p>정보를 제공하는 주체</p>
</li>
<li><p>파일을 읽어나 네트워크 작업을 하는 등의 시간이 오래 걸리는 작업을 수행하고, 수행한 결과에 대한 데이터나 에러를 반환한다</p>
<pre><code class="language-js">const promise = new Promise((resolve, reject) =&gt; {
  ... // executor
  setTimeout(() =&gt; {
      // 성공
      resolve(&#39;success!&#39;)

      // 실패
      reject(new Error(&#39;error!&#39;))
  }, 1000)
})</code></pre>
</li>
</ul>
<p><code>executor</code>의 로직(파일을 읽거나 네트워크 작업과 같은 작업)을 수행한 후 성공했을 때는 <code>resolve()</code>를 통해서 받아온 값을 전달할 수 있습니다.
반대로 실패한 경우에는 <code>reject()</code>와 <code>Error</code> 객체를 통해서 실패에 대한 값을 전달하게 됩니다.
<code>Error</code> 객체는 자바스크립트에서 제공하는 객체 중 하나입니다.</p>
<h2 id="consumer"><code>Consumer</code></h2>
<ul>
<li>정보를 사용하는 주체</li>
<li><code>new Promise</code> 생성자가 반환하는 <code>promise</code> 객체</li>
<li><code>then</code>, <code>catch</code>, <code>finally</code>를 이용해서 값을 받아올 수 있다</li>
</ul>
<h2 id="promise의-상태와-값-consumer의-상태"><code>Promise의 상태와 값</code> (<code>Consumer의 상태</code>)</h2>
<p><code>new Promise</code> 생성자가 반환하는 <code>Promise</code>는 상태(<code>status</code>)와 값(<code>result</code>)을 가지게 됩니다.
상태는 <code>pending</code>, <code>fulfilled</code>, <code>rejected</code>가 있고, 상태에 따라 값(<code>result</code>)이 바뀌게 됩니다.
이러한 상태의 변경은 <code>producer</code>에서 어떠한 함수를 호출하는가에 따라 달라지게 됩니다.</p>
<h3 id="pending"><code>pending</code></h3>
<ul>
<li><code>promise₩</code> 객체의 초기 상태 혹은 실행 중인 상태</li>
<li><code>result</code>는 <code>undefined</code></li>
</ul>
<h3 id="fulfilled"><code>fulfilled</code></h3>
<ul>
<li><code>producer</code>에서 <code>resolve</code>가 호출되면 나타나는 상태 (성공)</li>
<li><code>result</code>는 <code>resolve(value)</code>의 <code>value</code>로 값이 바뀌게 된다.</li>
</ul>
<h3 id="rejected"><code>rejected</code></h3>
<ul>
<li><code>producer</code>에서 <code>reject</code>가 호출되면 나타나는 상태 (실패)</li>
<li><code>result</code>는 <code>reject(error)</code>의 <code>error</code>로 값이 바뀌게 된다.</li>
</ul>
<h2 id="then-catch-finally"><code>then</code>, <code>catch</code>, <code>finally</code></h2>
<pre><code class="language-js">const promise = new Promise((resolve, reject) =&gt; {
    resolve(&#39;success!&#39;)
    reject(new Error(&#39;error!&#39;))
})</code></pre>
<h3 id="then"><code>then</code></h3>
<ul>
<li><code>resolve</code> 콜백 함수를 통해서 전달된 값을 사용할 수 있다</li>
<li>또한 <code>promise</code>도 전달할 수 있다.</li>
</ul>
<pre><code class="language-js">proimise
    .then((value) =&gt; console.log(value)) // success!</code></pre>
<p><code>value</code>라는 파라미터는 <code>resolve</code>에서 전달하는 값을 받는 파라미터입니다.
그래서 <code>value</code>라는 명칭을 고정해서 사용해야 하는 것은 아니고 적절한 명칭을 사용하면 됩니다.</p>
<h3 id="catch"><code>catch</code></h3>
<ul>
<li><code>reject</code> 콜백 함수를 통해서 전달된 에러에 대한 값을 사용할 수 있다</li>
</ul>
<pre><code class="language-js">promise
    .catch((error) =&gt; console.log(error)) // Error: error! at ...</code></pre>
<p><code>reject</code> 콜백함수에서 전달한 <code>error</code>에 대한 값을 <code>catch</code>로 받지 않게 되면 <code>Uncaught</code> 에러로 표현되게 됩니다.
그래서 에러 핸들링을 위해서 <code>catch</code>를 이용해서 실패에 대한 케이스를 처리해줘야 합니다.</p>
<h3 id="finally"><code>finally</code></h3>
<ul>
<li><code>executor</code>의 성공과 실패 여부와 상관없이 무조건 호출되는 함수</li>
</ul>
<pre><code class="language-js">promise
    .finally(() =&gt; console.log(&#39;finally!&#39;))</code></pre>
<p>만약 <code>promise</code>에 대한 <code>then</code>, <code>catch</code> 작업을 진행하고 싶다면 아래와 같이 <code>Promise Chaining</code> 형식으로 작성해야 합니다.
<code>.then</code>에 대한 반환 값도 <code>promise</code>이기 때문에, <code>.catch</code>에 대한 처리를 진행할 수 있습니다.</p>
<pre><code class="language-js">promise
    .then((value) =&gt; console.log(value))
    .catch((error) =&gt; console.log(error))</code></pre>
<pre><code class="language-js">const promise = new Promise((resolve, reject) =&gt; {
    console.log(&quot;doing something...&quot;);

    setTimeout(() =&gt; {
        reject(new Error(&quot;no network&quot;));
    }, 1000);
});

promise
    .then((value) =&gt; console.log(value))
    .catch((error) =&gt; console.log(error))
    .finally(() =&gt; console.log(&quot;finally&quot;));</code></pre>
<p>위와 같은 코드에서는 <code>Error: no network at ...</code>와 같은 메시지와 <code>finally</code> 문자열이 콘솔에 찍히게 될 것입니다.
만약 <code>catch</code>에 대한 처리를 해주지 않아도 <code>Uncaught</code>  에러와 함께 <code>finally</code>는 작동하게 됩니다.</p>
<h2 id="promise-chaining-and-error-handling"><code>Promise Chaining and Error Handling</code></h2>
<pre><code class="language-js">const getHen = () =&gt;

new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; resolve(&quot;hen&quot;), 1000);
});

const getEgg = (hen) =&gt;
    new Promise((resolve, reject) =&gt; {
    // setTimeout(() =&gt; resolve(`${hen} =&gt; egg`), 1000);
    setTimeout(() =&gt; reject(new Error(`error! ${hen} =&gt; egg`)));
});

const cook = (egg) =&gt;
    new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; resolve(`${egg} =&gt; fried`), 1000);
});



getHen()
    // .then((hen) =&gt; getEgg(hen))
    // callback 함수를 전달할 때 받아오는 value를 다른 함수에서 바로 호출하는 경우에는 생략이 가능하다.
    .then(getEgg)
    // egg를 받아올 때 문제가 생긴다면 catch를 통해서 다른 것을 전달해줄 수 있다.
    .catch(() =&gt; {
        return &quot;bread&quot;;
    })
.then((egg) =&gt; cook(egg))
.then((meal) =&gt; console.log(meal))
.catch(console.log);</code></pre>
<h2 id="마무리">마무리</h2>
<p>오늘은 <code>Promise</code>에 대해서 알아보았습니다.
자바스크립트 책을 한 권 스터디하는 것도 좋을 것 같다는 생각이 듭니다.. 🤔</p>
<p><code>Producer</code>와 <code>Consumer</code>의 개념을 사용한 것은 제가 참고한 유튜브에서 사용한 방식이기 때문에 공식적인 단어는 아닌 것으로 알고 있습니다.
해당 내용 참고하셔서 봐주시면 감사하겠습니다. 🙏</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=JB_yU6Oe2eE">https://www.youtube.com/watch?v=JB_yU6Oe2eE</a></li>
<li><a href="https://ko.javascript.info/promise-basics">https://ko.javascript.info/promise-basics</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Hook Form 이용해서 MUI 컴포넌트 제어하기]]></title>
            <link>https://velog.io/@s_sangs/React-Hook-Form-%EC%9D%B4%EC%9A%A9%ED%95%B4%EC%84%9C-MUI-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%A0%9C%EC%96%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@s_sangs/React-Hook-Form-%EC%9D%B4%EC%9A%A9%ED%95%B4%EC%84%9C-MUI-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%A0%9C%EC%96%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 29 May 2023 10:59:45 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>오늘은 <code>React Hook Form</code> 라이브러리를 이용해서 MUI와 같은 UI 라이브러리 컴포넌트를 제어하는 방법을 같이 나눠보려고 합니다.</p>
<p>우선 <code>React Hook Form</code> 라이브러리에 대한 개념 없이 MUI 컴포넌트를 제어하는 방법을 찾기까지 너무 힘들었습니다.. 💩</p>
<p>대부분의 포스팅에서는 <code>register</code>를 이용해서 <code>input</code>과 같은 컴포넌트를 제어하는 방법을 알려주고 있었는데요.
MUI에 적용하기에는 맞지 않는 방법이었고, 제 문제에 대한 해답을 찾기 위해서 굉장히 많은 시간을 사용했습니다. 😢</p>
<p>제가 출처에 남긴 포스팅의 방식을 찾는데 오래 걸린 것은 아니지만.. 문제에 대한 해결 방법이라는 것을 아는데 오래 걸렸던 것 같습니다.. ㅎㅎ</p>
<h2 id="1-controller-사용하기">1. <code>Controller</code> 사용하기</h2>
<p><code>React Hook Form</code> 라이브러리에서 제공하는 컴포넌트로, 외부 컴포넌트를 <code>React Hook Form</code>과 연결하여 제어하는데 사용됩니다.</p>
<h3 id="controller-기능"><code>Controller</code> 기능</h3>
<ul>
<li>외부 컴포넌트 연결: 외부 컴포넌트를 연결해서 필드를 제어할 수 있습니다.
값을 추적하거나 입력을 관리할 수 있습니다.</li>
<li>컴포넌트 속성 설정: <code>name</code>, <code>onChange</code>와 같은 속성을 외부 컴포넌트에 전달하여 필드의 상태를 업데이트 할 수 있습니다.</li>
<li>유효성 검증 규칙 설정: <code>rules</code> 속성을 사용하여 필드에 대한 유효성 검사 규칙을 정의할 수 있습니다.
유효성 검사는 자동으로 진행됩니다.</li>
</ul>
<pre><code class="language-ts">import { useForm, Controller } from &#39;react-hook-form&#39;;
import { TextField } from &#39;@mui/material&#39;;

const MyForm = () =&gt; {
    const { control, handleSubmit } = useForm();
    const onSubmit = (data) =&gt; console.log(data);

    return (
        &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
            &lt;Controller
                name=&#39;name&#39;
                control={control}
                rules={{ required: true }}
                render={({ filed }) =&gt; (
                    &lt;TextField
                        label=&#39;name&#39;
                        {...field}
                    /&gt;
                )}
        &lt;/form&gt;
    )
}</code></pre>
<p><code>render</code> 속성에서 렌더링할 컴포넌트를 정의하고 <code>field</code> 속성을 전달해서 해당 컴포넌트 제어를 <code>React Hook Form</code>에게 위임할 수 있습니다.</p>
<h2 id="2-usecontroller-사용하기">2. <code>useController</code> 사용하기</h2>
<p>이전에 사용한 <code>Controller</code> 컴포넌트와 동일한 권한을 가지는 커스텀 훅입니다.
추가적으로 <code>Controller</code>와 동일한 <code>props</code>와 <code>method</code>를 사용할 수 있습니다.</p>
<p><code>useController</code>는 재사용 가능한 컴포넌트를 만드는데 유용합니다.</p>
<h3 id="공식문서">공식문서</h3>
<pre><code class="language-ts">import { useForm, useController, UseControllerProps } from &quot;react-hook-form&quot;;

type FormValues = { FirstName: string; };

function Input(props: UseControllerProps&lt;FormValues&gt;) {
    const { field, fieldState } = useController(props);
    return (
        &lt;div&gt;
            &lt;input {...field} placeholder={props.name} /&gt;
        &lt;/div&gt;
    );
};

export default function App() {
    const { handleSubmit, control } = useForm&lt;FormValues&gt;({
        defaultValues: {
            FirstName: &quot;&quot;
        },
        mode: &quot;onChange&quot;
    })
    const onSubmit = (data: FormValues) =&gt; console.log(data)

return (
    &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
        &lt;Input control={control} name=&#39;FirstName&#39; rules={{ required: true }} /&gt;
    &lt;/form&gt;
    )
}</code></pre>
<p>위의 코드와 비교했을 때, <code>Controller</code> 컴포넌트를 사용하지 않고, 별도로 정의한 Input 컴포넌트를 제어할 수 있습니다.</p>
<p>하지만 예제에서는 특정 타입에서만 사용할 수 있도록 되어 있기 때문에 이 부분을 제너릭을 활용해서 공통 컴포넌트로 사용할 수 있도록 바꿔줘야 합니다.
추가적으로 별도로 정의한 Input 컴포넌트에 <code>MUI</code> 컴포넌트인 <code>textField</code>를 사용할 수 있지만, <code>textfieldProps</code>를 제대로 넘겨주지 못할 것입니다.</p>
<h2 id="usecontroller--mui-text-field"><code>useController + Mui Text Field</code></h2>
<pre><code class="language-ts">interface MuiProps {
    textFieldProps?: TextFieldProps;
}

const Input = &lt;
    TFieldValues extends FieldValues = FieldValues,
    TName extends FieldPath&lt;TFieldValues&gt; = FieldPath&lt;TFieldValues&gt;
&gt;({
    textFieldProps,
    ...props
}): MuiProps &amp; UseController&lt;TfieldValues, TName&gt;) =&gt; {
    const { field, fieldState: { error } } = useController(props)

    return (
        &lt;TextField
            {...textFieldProps}
            {...field}
            error={!!error}
            helperText={!!error &amp;&amp; error.message}
        /&gt;
    )
}</code></pre>
<h2 id="사용">사용</h2>
<pre><code class="language-ts">const App = () =&gt; {
    const { control, handleSubmit } useForm()

    const onSubmit = (data) =&gt; console.log(data)

    return (
        &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
            &lt;Input
                name=&quot;FirstName&quot;
                control={control}
                rules={{ required: true }}
                textFIeldProps={{
                    label: &quot;First Name&quot;
                }}
        &lt;/form&gt;
    )
}</code></pre>
<p>개인적으로 <code>Controller</code> 컴포넌트를 사용하는 것보다 깔끔하고 편하다고 생각합니다.</p>
<p>추가적으로, 마지막의 <code>useController</code>와 <code>MUI</code>의 <code>textField</code> 컴포넌트를 같이 사용하는 방식은 제가 참고한 포스팅에 훨씬 자세한 설명이 있으니 원문을 참고하시는 것도 좋을 것 같습니다! 🙏🙇‍♂️</p>
<p>만약 저처럼 <code>React Hook Form</code> 라이브러리와 <code>MUI</code>를 같이 사용하고 싶다면, 결국 <code>TextFieldProps</code>를 별도로 처리해줘야 합니다!</p>
<ol>
<li><code>Controller</code> 컴포넌트 활용하기</li>
<li><code>useController</code> 훅 활용하기
가독성이나 선호도 차이에 따라 위의 2가지 방법 중 선택해서 사용하면 될 것 같습니다!
저의 경우에는 <code>useController</code> 훅을 활용해서 별도로 정의한 Input 컴포넌트를 만들었습니다!</li>
</ol>
<h2 id="마무리">마무리</h2>
<p>개인적으로 이번 학습에 처음으로 챗 GPT를 많이 사용한 것 같습니다..
이전까지는 아직 챗 GPT를 믿을 수 없다는 생각이 많이 있어서 전혀 사용하지 않았는데요.
시간도 부족하고 막막한 느낌이 있어서 사용했더니.. 저에게 좋은 경험을 준 것 같습니다. 👍</p>
<p>그리고 <code>React Hook Form</code>의 공식문서는 너무나도 잘 되어있다는 생각이 들었습니다.
처음부터 공식문서를 살펴 볼 시간이 있었다면.. 오히려 더 빠르게 해결 할 수 있지 않았을까? 라는 생각이 들었네요!</p>
<ul>
<li>해결의 결정타를 날려준 포스팅 주인님 🙏</li>
<li>정보의 중심이 되는 공식문서 📚</li>
<li>나의 시간을 많이 아껴준 챗GPT ⚙️</li>
</ul>
<p>삼박자가 잘 맞는 아주 값진 경험이었습니다..⭐️</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://velog.io/@syoo970/react-hook-form%EA%B3%BC-MUI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%9E%AC%EC%82%AC%EC%9A%A9%EC%84%B1-%EC%9E%88%EB%8A%94-Input-%EA%B3%B5%ED%86%B5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0TypeScript">https://velog.io/@syoo970/react-hook-form%EA%B3%BC-MUI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%9E%AC%EC%82%AC%EC%9A%A9%EC%84%B1-%EC%9E%88%EB%8A%94-Input-%EA%B3%B5%ED%86%B5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0TypeScript</a></li>
<li><a href="https://react-hook-form.com/docs/usecontroller">https://react-hook-form.com/docs/usecontroller</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[@media 정리]]></title>
            <link>https://velog.io/@s_sangs/media-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@s_sangs/media-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 27 May 2023 16:39:46 GMT</pubDate>
            <description><![CDATA[<p>사용자에게 적합한 레이아웃을 제공하기 위해서 <code>media query</code>를 사용합니다.
미디어 쿼리는 단말기의 유형이나 해상도에 따라 웹 사이트나 앱의 스타일을 수정할 때 유용합니다.</p>
<h2 id="미디어-유형">미디어 유형</h2>
<p>장치의 일반적인 범주를 나타냅니다.
<code>not</code>이나 <code>only</code> 논리 연산자를 사용할 때를 제외하면 선택사항이며 <code>default value</code>는 <code>all</code>입니다.</p>
<ul>
<li><code>all</code>: 모든 장치에 적합</li>
<li><code>print</code>: 인쇄 결과물 및 출력 미리보기 화면에 표시중인 문서</li>
<li><code>screen</code>: 주로 화면이 대상</li>
<li><code>speech</code>: 음성 합성 장치 대상</li>
</ul>
<br>

<h2 id="논리-연산자">논리 연산자</h2>
<p><code>not</code>, <code>and</code>, <code>only</code>와 같은 논리 연산자를 사용해 쿼리를 조합할 수 있습니다.</p>
<ul>
<li><code>and</code>: 다수의 미디어 특성을 조합해서 하나의 미디어 쿼리를 만듬. 쿼리가 참이려면 모든 구성 특성이 참을 반환해야 한다.</li>
<li><code>not</code>: 쿼리가 거짓일 때만 참을 반환한다. 쉼표로 구분한 쿼리 목록 중 하나에서 사용한 경우 전체 쿼리가 아닌 해당하는 하나의 쿼리에만 적용된다.</li>
<li><code>only</code>: 전체 쿼리가 일치할 때만 스타일을 적용할 수 있도록 사용, 오래 된 브라우저가 스타일을 잘못 적용하지 못하도록 방지할 때 유용하다. </li>
<li>쉼표(<code>,</code>): 다수의 미디어 쿼리를 하나의 규칙으로 조합할 때 사용, 하나의 쿼리만 참을 반환해도 규칙 전체가 참이 된다. 논리 연산자 <code>or</code> 처럼 동작한다.</li>
</ul>
<blockquote>
<p>Level 3 모듈에서는 <code>not</code> 키워드를 사용해 단일 미디어 기능을 부정할 수 없고 전체 쿼리만 부정이 가능합니다.</p>
</blockquote>
<blockquote>
<p>예전의 구형 브라우저에서는 <code>screen and (max-width: 500px)</code> 이라는 쿼리를 단순하게 <code>screen</code>으로만 읽고 스타일을 적용해버렸습니다.
이러한 경우 <code>only screen and (max-width: 500px)</code> 식으로 표현해서 전체 쿼리가 일치 할 때만 스타일을 적용할 수 있도록 설정합니다.
<strong><code>only</code> 키워드를 사용할 때는 미디어 유형을 필수로 지정해야합니다.</strong></p>
</blockquote>
<br>

<h2 id="미디어-기능-특정">미디어 기능 특정</h2>
<p>사용자, 출력 장치, 주변 환경 특징을 설명합니다.</p>
<pre><code class="language-css">@media (hover: hover) { ... }</code></pre>
<pre><code class="language-css">@media (max-width: 1024px) { ... }</code></pre>
<p>첫 번째 쿼리는 마우스가 호버할 수 있으면 스타일을 적용합니다.
<code>css</code>를 많이 사용해본 것은 아니지만, 대부분 이러한 기능을 사용할 때 주료 <code>max-width</code>와 같은 범위 기능을 주로 사용한 것 같습니다.</p>
<blockquote>
<p>특정 기능이 현재 브라우저에 적용되지 않으면, 해당 미디어 기능을 포함한 표현식은 항상 거짓입니다.</p>
</blockquote>
<br>

<h2 id="유형과-기능을-연산자로-조합하기">유형과 기능을 연산자로 조합하기</h2>
<p>미디어의 유형과 미디어 기능을 논리 연산자로 조합해서 다양하게 사용할 수 있습니다.</p>
<br>

<pre><code class="language-css">@media screen and (max-width: 1024px) { ... }</code></pre>
<p>기본적으로 반응형에 이용하기 위해서 많이 사용하는 쿼리 입니다.
나눠서 보면 미디어 유형으로 <code>screen</code>, 미디어 기능으로 <code>max-width: 1024px</code>, 논리 연산자로 <code>and</code>가 포함되어 있습니다.</p>
<p>풀어서 해석하면 <strong>주로 화면이 대상인 미디어의 넓이가 1024px인 장치</strong>라고 이해할 수 있습니다.</p>
<br>

<pre><code class="language-css">@media not all and (monochrome) { ... }</code></pre>
<p><code>not</code> 연산자는 미디어 쿼리 전체의 의미를 반전시킵니다. (Level 3 모듈 기준)
<code>@media not (all and (monochrome)) { ... }</code>와 동일한 의미를 가지게 됩니다.</p>
<br>

<pre><code class="language-css">@media not screen and (color), print and (color) { ... }</code></pre>
<p>하지만 쉼표(<code>,</code>)가 포함되어 있다면, 다른 방식으로 반전이 됩니다.
쉼표를 기준으로 쿼리를 구분짓기 때문에 해당 미디어 쿼리는 <code>not screen and (color)</code>와 <code>print and (color)</code> 두 개의 쿼리로 구분짓게 됩니다.
기본적으로 <code>not</code>은 쿼리 전체를 부정하게 됩니다. (<code>Level 4 제외</code>)
이러한 경우 <code>@media not (screen and (color)), print and (color) { ... }</code> 동일하게 해석이 됩니다.</p>
<br>

<h2 id="level-4의-구문-향상">Level 4의 구문 향상</h2>
<h3 id="범위-지정">범위 지정</h3>
<p>미디어 쿼리 Level 4는 향상된 기능을 제공하는데, 대표적으로  미디어쿼리가 &#39;범위&#39; 유형을 가진 기능을 사용할 수 있습니다.</p>
<p>자주 사용하던 <code>@media (max-width: 1024px) { ... }</code>와 같은 쿼리는 Level 4에서는 <code>@media (width &lt;= 1024px) { ... }</code>와 같이 사용할 수 있습니다.
<code>max-</code>, <code>min-</code>과 같은 키워드를 사용하지 않고 <strong>범위</strong>로 지정할 수 있습니다.</p>
<h3 id="not으로-기능-부정"><code>not</code>으로 기능 부정</h3>
<p>Level 3 모듈까지는 쿼리 전체를 부정할 수 있었는데, 기능을 부정할 수 있습니다.</p>
<pre><code class="language-css">@media (not(hover)) { ... }</code></pre>
<p><code>hover</code>를 할 수 없는 장치를 사용할 때 <code>not(hover)</code>를 사용할 수 있습니다.</p>
<h3 id="or로-다수의-기능-판별"><code>or</code>로 다수의 기능 판별</h3>
<p>다수의 기능 가운데 하나라도 있는지 테스트해서 그 중에 하나라도 참이라면 <code>true</code>를 반환할 수 있습니다.</p>
<pre><code class="language-css">@media (not (color)) or (hover) { ... } </code></pre>
<p><strong>해당 쿼리의 의미는 컬러화면이 아니거나 <code>hover</code> 기능이 지원이 되지 않을 때</strong>를 의미합니다.</p>
<p>개인적으로 쉼표와 조금 헷갈렸는데요.. 🤯
쉼표(<code>,</code>)는 <strong>다수의 미디어 쿼리를 하나의 규칙으로 조합</strong>하는게 포인트입니다.
쿼리로 구분짓지 않고, 하나의 쿼리에 다수의 기능을 작성할 때는 <code>or</code>을 사용하는 것이 좋아보입니다.</p>
<blockquote>
<p>미디어쿼리 Level 4 사앙에는 상당수의 최신 브라우저를 지원하지만, 몇몇 미디어 기능들은 잘 지원되지 않습니다.</p>
</blockquote>
<h2 id="마무리">마무리</h2>
<p>사실 이전부터 <code>only</code>라는 키워드를 왜 써야하지?🤔라는 생각을 하면서 그냥 복사, 붙여넣기 식으로 많이 사용했던 것 같습니다.
마냥 반응형이라고 하면 <code>@media only screen and (min, max-width: ...) { ... }</code>와 같은 쿼리만 입력하고 <code>breakpoint</code>만 넣어뒀으니까요.. 🤣</p>
<p><code>Leve 4</code>라는 구분점이 있는지도 오늘 처음 알았습니다.. ㅎㅎ
MDN의 미디어 쿼리 사용하기 페이지를 한 번 쭉 보았는데요!</p>
<p>오늘도 제대로 된 이유를 모르고 사용하던 기능을 알게 되서 만족스럽습니다 👍</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://developer.mozilla.org/ko/docs/Web/CSS/CSS_media_queries/Using_media_queries#%ea%b5%ac%eb%ac%b8">https://developer.mozilla.org/ko/docs/Web/CSS/CSS_media_queries/Using_media_queries#%ea%b5%ac%eb%ac%b8</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js에 Emotion 적용하기]]></title>
            <link>https://velog.io/@s_sangs/Next.js%EC%97%90-Emotion-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@s_sangs/Next.js%EC%97%90-Emotion-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 27 May 2023 11:25:35 GMT</pubDate>
            <description><![CDATA[<p><code>Next.js</code>에 전체적으로 <code>Emotion</code>을 적용하는 방법을 알아보려고 합니다.</p>
<p>회사에서 주로 모바일 웹앱으로 작업을 하다가 새로운 프로젝트를 작업하게 됐는데요.
반응형 웹으로 작업을하고 초기세팅까지 하려고 하니 익숙하지 않은 부분이 많았습니다 😢</p>
<h2 id="global-style-적용하기"><code>Global Style</code> 적용하기</h2>
<p><code>emotion</code>에서 제공하는 <code>Global</code> 컴포넌트를 이용해서 적용할 수 있습니다.</p>
<p><code>styles/</code> 디렉터리를 생성한 뒤 <code>Global.tsx</code> 파일을 생성합니다.
그리고 아래와 같이 코드를 작성해줍니다.</p>
<pre><code class="language-ts">// Global.tsx
import { Global, css } from &#39;@emotion/react&#39;

const style = css`
    html,
    body {
        margin: 0;
        padding: 0;
        font-size: 16px;
    }
`

const GlobalStyle = () =&gt; &lt;Global styles={styles} /&gt;

export default GlobalStyle</code></pre>
<p>해당 파일에 리셋과 관련된 <code>css</code>를 포함해도 좋다고 생각합니다.
최근에는 <code>reset.css</code>와 <code>normalize.css</code>를 섞어서 사용하거나 사용성에 맞게 사용하는 추세라고 합니다.</p>
<p>이후 <code>pages/_app.tsx</code> 에서 해당 <code>Global Style</code>을 적용합니다.</p>
<pre><code class="language-ts">// _app.tsx
import { GlobalStyle } from &#39;@/styles/Global&#39;

const App = ({ Component, pageProps }) =&gt; {
    return (
        &lt;Layout&gt;
            &lt;GlobalStyle /&gt;
            &lt;Component {...pageProps} /&gt;
        &lt;/Layout&gt;
    )
}</code></pre>
<blockquote>
<p><code>reset</code>과 <code>normalize</code>
웹 브라우저(<code>chrome</code>, <code>fireforx</code> 등)마다 기본적으로 제공하는 스타일이 다르게 적용되어 있습니다.
브라우저 별로 일관된 스타일을 제공해야 되는 입장으로 이러한 기본적인 스타일을 초기화(<code>reset</code>)하거나 동일하게 유지(<code>normalize</code>)할 필요가 있습니다.</p>
</blockquote>
<br>

<h2 id="themeprovider-적용하기"><code>ThemeProvider</code> 적용하기</h2>
<p>다크모드나 사용자 테마를 적용하기 위해서 사용되는 컴포넌트입니다.
<code>emotion</code>에서 제공하는 <code>ThemeProvider</code> 컴포넌트를 이용해서 적용할 수 있습니다.</p>
<p><code>styles/</code> 디렉터리에서 <code>theme.ts</code> 파일을 생성합니다.</p>
<pre><code class="language-ts">// theme.ts
import { Theme } from &#39;@emotion/react&#39;

const theme: Theme = {
    color: {
        black: &#39;#000&#39;,
        white: &#39;#fff&#39;,
    }
}

export default theme</code></pre>
<br>

<p>이후 <code>pages/_app.tsx</code>에서 테마를 적용합니다.</p>
<pre><code class="language-ts">// _app.tsx
import { GlobalStyle } from &#39;@/styles/Global&#39;
import { ThemeProvider } from &#39;@emotion/react&#39;
import theme from &#39;@/styles/theme&#39;

const App = ({ Component, pageProps }) =&gt; {
    return (
    &lt;ThemeProvider theme={theme}&gt;
        &lt;Layout&gt;
            &lt;GlobalStyle /&gt;
            &lt;Component {...pageProps} /&gt;
        &lt;/Layout&gt;
    &lt;/ThemeProvider&gt;
    )
}</code></pre>
<br>

<h2 id="serializedstyles-활용하기"><code>SerializedStyles</code> 활용하기</h2>
<p>반응형 컴포넌트나 레이아웃 사용하기 위해서는 <code>media query</code>와 <code>breakpoint</code>를 피할 수 없는데요.
<code>emotion</code>에서 제공하는 <code>SerializedStyles</code>를 이용해서 조금 더 간편하게 반응형을 사용할 수 있습니다.</p>
<p><code>media query</code>를 컴포넌트처럼 분리해서 사용하는 방식입니다.
<code>styles/</code> 디렉터리에 <code>mediaQuery.ts</code> 파일을 생성합니다.</p>
<br>

<pre><code class="language-ts">//mediaQuery.ts
import { SerializedStyles, css } from &#39;@emotion/react&#39;

const breakPoints = {
    desktop: 1920,
    tablet: 1439,
    mobile: 767,
}

export const MobileStyle = (style: SerialzedStyles) =&gt; css`
    @media screen and (max-width: ${breakPoints.mobile}px) {
        ${style}
    }
`</code></pre>
<p><code>Emotion Composition</code>의 기능을 이용해서 구현합니다.
<code>Emotion Composition</code>은 두 개 이상의 스타일 객체를 결합하여 새로운 객체를 생성합니다.
<code>css</code> 스타일을 넘겨주고 <code>media query</code>가 적용된 스타일을 내보내는 모듈 역할을 합니다.</p>
<br>

<pre><code class="language-ts">// styles.ts

import styled from &#39;@emotion/styled&#39;

export const Container = styled.div`
    width: 100%;

    ${MobileStyle(css`
        font-size: 1.5rem;
        font-weight: 700;
    `)}
`</code></pre>
<p>매번 <code>media query</code>와 <code>breakpoint</code>를 가져와서 사용하는 것이 아니기 때문에 중복 코드를 줄일 수 있습니다.</p>
<h2 id="마무리">마무리</h2>
<p>최근에 새로운 프로젝트를 진행하면서 처음 써보는 <code>Next.js</code>와 여러 라이브러리들에 대한 정리를 제대로 하지 못한 것 같습니다. 😭
최근에 <code>Next.js</code>를 비롯해서 <code>ReactQuery</code>, <code>React-Hook-Form</code> 등 처음 사용해보는 기술 및 도구들이 많아졌습니다..
출시 기간에 맞추다보니 이해하지 않고 사용하는 부분들이 많았는데, 이렇게 하나씩 정리하면서 이해하고 사용하는 개발자가 됐으면 합니다.. 🙏</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://emotion.sh/docs/globals">https://emotion.sh/docs/globals</a></li>
<li><a href="https://velog.io/@moon_l/Next.js-Emotion-%EA%B8%80%EB%A1%9C%EB%B2%8C-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0">https://velog.io/@moon_l/Next.js-Emotion-%EA%B8%80%EB%A1%9C%EB%B2%8C-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</a></li>
<li><a href="https://mine-it-record.tistory.com/598">https://mine-it-record.tistory.com/598</a></li>
<li><a href="https://hailey0930.github.io/css/2023/04/17/CSS_refactoring/#/">https://hailey0930.github.io/css/2023/04/17/CSS_refactoring/#/</a></li>
<li><a href="https://emotion.sh/docs/composition">https://emotion.sh/docs/composition</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript + ESLint + Prettier 설정하기]]></title>
            <link>https://velog.io/@s_sangs/TypeScript-ESLint-Prettier</link>
            <guid>https://velog.io/@s_sangs/TypeScript-ESLint-Prettier</guid>
            <pubDate>Mon, 15 May 2023 21:55:22 GMT</pubDate>
            <description><![CDATA[<p>CRA로 구축할 때 타입스크립트를 기본으로 사용하는 프로젝트에서 <code>eslint</code>와 <code>prettier</code>를 설정하는 방법을 남겨보려고 합니다!</p>
<p>기본적으로 타입스크립트로 언어를 설정하고 <code>CRA</code>를 통해서 프로젝트를 생성했다면 <code>typescript-eslint</code>를 사용하면 됩니다.</p>
<p>전체적인 플로우는</p>
<ol>
<li><code>typescript-eslint</code>와 관련된 라이브러리 설치 및 <code>.eslintrc.js</code> 파일 설정</li>
<li><code>prettier</code> 라이브러리 설치</li>
<li><code>prettier</code>와 <code>eslint</code>를 같이 사용할 수 있는 라이브러리 설치 및 <code>.eslintrc.js</code> 파일 설정</li>
<li>본인 기호에 맞게 <code>.prettierrc.js</code> 파일 설정</li>
</ol>
<h2 id="typescript-eslint"><code>typescript-eslint</code></h2>
<p>타입스크립트 코드를 <code>linting</code>해주는 도구입니다.
<code>eslint</code>와 <code>typescript</code>는 각자의 <code>parser</code>를 통해서 서로 다른 AST(Abstract Syntax Tree)를 만들어 내는데,
이렇게 다른 AST로 인해 생겨나는 문제점을 해결하기 위해서 생겨난 도구입니다.</p>
<p><code>typescript-eslint</code>를 통해 <code>eslint</code>와 <code>typescript</code>가 함께 사용할 수 있게 됐습니다.</p>
<h2 id="eslint-설정"><code>ESLint</code> 설정</h2>
<h3 id="eslint"><code>ESLint</code></h3>
<ul>
<li>ESLint는 ES와 Lint의 합성어</li>
<li>ECMA Script + Lint로써 표준 자바스크립트 문법에서 에러를 표시해주는 도구</li>
<li>버그를 사전에 방지, <code>tab</code>이나 줄바꿈 등의 코딩 스타일을 정의함으로써 협업에 도움이 된다.</li>
</ul>
<h3 id="eslint-관련-라이브러리-설치">ESLint 관련 라이브러리 설치</h3>
<pre><code class="language-bash">yarn add --dev eslint</code></pre>
<blockquote>
<p><a href="mailto:eslint@8.22.0">eslint@8.22.0</a> 버전에 대한 문제가 생긴다면 아래의 명령어로 라이브러리를 설치하면 됩니다.</p>
</blockquote>
<pre><code class="language-bash">yarn add --dev eslint@8.22.0 --save-exact</code></pre>
<br>



<h3 id="typescript-eslint-관련-라이브러리-설치"><code>typescript-eslint</code> 관련 라이브러리 설치</h3>
<pre><code class="language-bash">yarn add --dev @typescript-eslint/eslint-plugin @typescript-eslint/parser</code></pre>
<h4 id="typescript-eslintparser"><code>@typescript-eslint/parser</code></h4>
<ul>
<li>타입스크립트 코드에 대한 AST 생성</li>
</ul>
<h4 id="typescript-eslinteslint-plugin"><code>@typescript-eslint/eslint-plugin</code></h4>
<ul>
<li><code>typescript-eslint</code>의 규칙들을 사용할 수 있게 해준다.</li>
</ul>
<br>


<h3 id="eslintrccjs-설정"><code>.eslintrc.cjs</code> 설정</h3>
<pre><code class="language-javascript">module.exports = {  
    root: true,
    // eslint에 어떠한 parser를 사용할지 알려주는 옵션
    // eslint가 typescript 문법을 이해할 수 있게 해준다.
    parser: &#39;@typescript-eslint/parser&#39;,
    // typescript-eslint에서 제공하는 규칙들을 사용할 수 있게 해준다.
    plugins: [&#39;@typescript-eslint&#39;],  
    // 어떠한 규칙들과 설정으로 eslint를 사용할지 명시한다.
    // 아래와 같이 작성하면 default 값으로 적용이 된다.
    extends: [
        &#39;eslint:recommended&#39;,
        &#39;plugin:@typescript-eslint/recommended&#39;,
    ],

    rules: {
        // 세미콜론이 없으면 에러로 취급한다.
        semi: &#39;error&#39;,
        // 기존 프로젝트에서는 &#39;warn&#39;으로 취급되지만, &#39;error&#39;로 설정하면 에러로 취급한다.
        &#39;@typescript-eslint/no-unused-vars&#39;: &#39;error&#39;
    }
};</code></pre>
<blockquote>
<p>만약 프로젝트에서 ESM을 사용할 수 없다면 .eslintrc.js로 파일명을 사용하면 됩니다.</p>
</blockquote>
<br>


<h3 id="eslintignore-파일-작성"><code>.eslintignore</code> 파일 작성</h3>
<p><code>eslint</code>를 적용하지 않을 파일이나 폴더를 적어줍니다.</p>
<pre><code>// .eslintignore
node_modules
dist</code></pre><h3 id="linting-방법">Linting 방법</h3>
<pre><code class="language-bash">yarn eslint . --ext .js,.jsx,.ts,.tsx
npx eslint . --ext .js,.jsx,.ts,.tsx</code></pre>
<br>

<h2 id="prettier-설정"><code>Prettier</code> 설정</h2>
<h3 id="prettier"><code>Prettier</code></h3>
<ul>
<li>정해진 규칙에 따라 자동으로 코드 스타일을 정리해주는 도구</li>
<li>여러 규칙들을 쉽게 커스터마이징 할 수 있다.</li>
</ul>
<blockquote>
<p><code>prettier</code>는 코드 포맷팅에 특화되어 있으므로 <code>eslint</code>가 할 수 없는 최대 글자 길이에 맞춘 자동 포맷팅을 할 수 있다.</p>
</blockquote>
<br>

<h3 id="prettier-관련-라이브러리-설치"><code>Prettier</code> 관련 라이브러리 설치</h3>
<pre><code class="language-bash">yarn add --dev prettier</code></pre>
<p>추가적으로 각자 사용하는 <code>IDE</code>에서 <code>prettier</code>를 설정해주면 됩니다!</p>
<br>

<h2 id="prettier와-eslint를-동시에-사용하기"><code>Prettier</code>와 <code>ESLint</code>를 동시에 사용하기</h2>
<p><code>prettier</code>와 <code>eslint</code>를 동시에 사용하는 방법은 여러가지 방법이 있습니다.</p>
<h3 id="1-prettier-eslint"><code>1. prettier-eslint</code></h3>
<ul>
<li><code>prettier</code>를 실행 후 <code>eslint</code>를 실행하는 방법</li>
<li><code>prettier-eslint</code> <strong>메인테이너도 2017년 이미 이 패키지를 사용하지 않는다.</strong></li>
</ul>
<br>

<h3 id="2-eslint-config-prettier"><code>2. eslint-config-prettier</code></h3>
<ul>
<li><code>eslint</code>에서 <code>prettier</code>와 충돌하는 <code>eslint</code> 규칙을 전부 꺼주는 방법</li>
<li>코드 오류를 잡는데는 <code>eslint</code>를 코드 포맷팅에는 <code>prettier</code>를 사용하는 방법이다.</li>
<li>두 개의 역할을 구분하는 것이 좋으므로 이 방법을 추천한다.</li>
</ul>
<h4 id="라이브러리-설치">라이브러리 설치</h4>
<pre><code class="language-bash">yarn add --dev eslint-config-prettier</code></pre>
<h4 id="eslintrccjs-파일-수정"><code>.eslintrc.cjs</code> 파일 수정</h4>
<pre><code class="language-javascript">{
  &quot;extends&quot;: [
    &quot;some-other-config-you-use&quot;,
    // prettier 추가
    &quot;prettier&quot;
  ]
}</code></pre>
<blockquote>
<p><code>prettier/@typescript-eslint</code>는 <code>eslint-config-prettier</code> v8.0.0에서 지워졌다.
그렇기 때문에 <code>eslint-config-prettier</code> 버전이 8이상이라면 <code>prettier/@typescript-eslint</code>를 지우면 됩니다.</p>
</blockquote>
<br>


<h3 id="3-eslint-plugin-prettier"><code>3. eslint-plugin-prettier</code></h3>
<ul>
<li>린터인 것처럼 <code>prettier</code>를 실행하는 플러그인</li>
<li>특정 상황에서 유용할 수 있지만, <code>prettier</code>를 직접 실행하는 것보다 느리다.</li>
<li>포맷팅 문제도 오류로 출력되어서 오류 메시지가 지나치게 많다.</li>
</ul>
<h4 id="라이브러리-설치-1">라이브러리 설치</h4>
<pre><code class="language-shell">yarn add --dev eslint-plugin-prettier</code></pre>
<h4 id="eslintrccjs-파일-수정-1"><code>.eslintrc.cjs</code> 파일 수정</h4>
<pre><code class="language-javascript">module.exports = {  
 root: true,  
 parser: &#39;@typescript-eslint/parser&#39;,  

    // prettier 추가
 plugins: [&#39;@typescript-eslint&#39;, &#39;prettier&#39;],  
 extends: [  
  &#39;eslint:recommended&#39;,  
  &#39;plugin:@typescript-eslint/recommended&#39;,  
  // prettier 삭제
  // &#39;prettier&#39; 

  // plugin:prettier/recommended 추가
  &#39;plugin:prettier/recommended&#39;  
 ],  

 rules: {
    //prettier/prettier rule 추가
  &#39;prettier/prettier&#39;: &#39;error&#39;,    
  semi: &#39;error&#39;,  
  &#39;@typescript-eslint/no-unused-vars&#39;: &#39;error&#39;,  

 }  
};</code></pre>
<p>해당 방법은 <code>eslint-config-prettier</code> 라이브러리와 같이 사용하는 방법입니다.
<code>eslint-plugin-prettier</code>를 제대로 사용하기 위해서는 <code>formatting</code>에 관련한 모든 <code>eslint</code> 규칙을 꺼야합니다.
그러지 않으면 에러가 발생하게 됩니다.</p>
<p>그래서 공식문서에서도 <code>formatting</code>에 관련한 모든 <code>eslint</code> 규칙을 비활성화하기 위해서 <code>eslint-config-prettier</code> 설치를 하나의 솔루션으로 제공하고 있습니다.</p>
<p>해당 방식을 통해서 <code>eslint</code>만 이용해서 문법 검사와 <code>formatting</code>을 함께 실행시킬 수 있습니다.
하지만 <code>prettier</code>를 직접 실행하는 것보다 속도가 느리고 오류 메시지가 지나치게 많다는 단점도 있기 때문에 선호하는 방식으로 사용하면 될 것 같습니다!</p>
<h3 id="prettierrcjs-파일-설정"><code>.prettierrc.js</code> 파일 설정</h3>
<pre><code class="language-javascript">//.prettierrc.js  

module.exports = {  
  // 문자열은 따옴표로 formatting
  singleQuote: true,  
  //코드 마지막에 세미콜른이 있게 formatting
  semi: true,  
  //탭의 사용을 금하고 스페이스바 사용으로 대체하게 formatting
  useTabs: false,  
  // 들여쓰기 너비는 2칸  
  tabWidth: 2,  
  // 코드 한줄이 maximum 80칸  
  printWidth: 80,  
};</code></pre>
<br>


<h2 id="출처">출처</h2>
<ul>
<li><a href="https://typescript-eslint.io/getting-started">https://typescript-eslint.io/getting-started</a></li>
<li><a href="https://stackoverflow.com/questions/65675771/eslint-couldnt-find-the-config-prettier-typescript-eslint-after-relocating">https://stackoverflow.com/questions/65675771/eslint-couldnt-find-the-config-prettier-typescript-eslint-after-relocating</a></li>
<li><a href="https://gingerkang.tistory.com/97">https://gingerkang.tistory.com/97</a></li>
<li><a href="https://velog.io/@_jouz_ryul/ESLint-Prettier-Airbnb-Style-Guide%EB%A1%9C-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0#22-eslint-config-prettier--eslint-plugin-prettier">https://velog.io/@_jouz_ryul/ESLint-Prettier-Airbnb-Style-Guide%EB%A1%9C-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0#22-eslint-config-prettier--eslint-plugin-prettier</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js page.tsx 사용하기]]></title>
            <link>https://velog.io/@s_sangs/Next.js-page.tsx-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@s_sangs/Next.js-page.tsx-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 08 May 2023 22:58:12 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>Next.js의 <code>pageExtensions</code> 기능을 통해서 <code>index.page.tsx</code>와 같은 형식으로 페이지를 표현할 수 있습니다!</p>
<p><code>pageExtensions</code>는 <code>next.config.json</code> 옵션 중 하나로 특정 형식의 이름을 페이지로 인식하는 기능입니다.
이렇게 사용하는 이유는 페이지 디렉터리 안에서 페이지 파일을 구분하기 위해서 입니다!</p>
<p>스타일을 별도의 <code>ts</code>나 <code>tsx</code>로 관리하게 된다면, 해당 파일을 페이지로 인식하게 됩니다.
추가적으로 테스트 파일이나 별도의 컴포넌트 파일을 가지게 된다면 해당 파일도 페이지로 인식하게 됩니다. 😢</p>
<p>저의 경우에는 <code>styles.ts</code> 파일로 스타일을 관리하는데요.
아직 테스트 코드는 작성하고 있지 않지만, 테스트 코드도 추가하게 된다면, 더더욱 페이지 파일을 구분해야 할 것 같습니다.</p>
<h2 id="공식-문서">공식 문서</h2>
<h3 id="pageextensions">pageExtensions</h3>
<p><code>Next.js</code>에서 사용 중인 기본 페이지 확장자(<code>.tsx</code>, <code>ts</code>, <code>jsx</code>, <code>js</code>)을 확장할 수 있습니다.
<code>next.config.js</code> 파일 안에 <code>pageExtensions</code> 설정을 추가합니다.</p>
<pre><code class="language-js">module.exports = {
  pageExtensions: [&#39;mdx&#39;, &#39;md&#39;, &#39;jsx&#39;, &#39;js&#39;, &#39;tsx&#39;, &#39;ts&#39;],
};</code></pre>
<p>위의 값을 변경하게 되면 Next.js의 아래를 포함한 모든 페이지에 영향이 가게 됩니다.</p>
<ul>
<li><code>middleware.js</code></li>
<li><code>pages/_document.js</code></li>
<li><code>pages/_app.js</code></li>
<li><code>pages/api/</code></li>
</ul>
<p>예를 들어, <code>.ts</code> 페이지 확장자를 <code>.page.ts</code>로 재설정하게 된다면, <code>_app.page.ts</code>와 같이 페이지들의 이름을 수정해야 합니다.</p>
<h3 id="including-non-page-file-in-the-pages-directory">Including non-page file in the <code>pages</code> directory</h3>
<p>테스트 파일이나 컴포넌트로 사용되는 다른 파일들을 <code>pages</code> 디렉터리에 같이 배치할 수 있습니다.
이러한 경우에는 <code>next.config.js</code> 파일 안에 <code>pageExtensions</code> 설정을 추가합니다.</p>
<pre><code class="language-js">module.exports = {
  pageExtensions: [&#39;page.tsx&#39;, &#39;page.ts&#39;, &#39;page.jsx&#39;, &#39;page.js&#39;],
};</code></pre>
<p>그리고, 페이지의 이름을  <code>.page</code>가 포함된 파일명으로 바꿔줍니다. (예를 들어 <code>MyPage.tsx</code>를 <code>MyPage.page.tsx</code>로 이름을 바꿔줍니다.) 위에 언급된 파일들을 포함해서 모든 Next.js 페이지의 이름을 변경해야 합니다.</p>
<h2 id="마무리">마무리</h2>
<p>공식문서를 확인하기 전에는 Next.js가 페이지를 구분하기 위한 기능이라고 생각하기 보다는 개발자의 가시성을 위한 기능이라고 생각했습니다. ㅎㅎ</p>
<p>스타일 코드 및 테스트 코드를 작성하다 보면 <code>pages</code> 디렉터리 안에 페이지 파일만 존재하는 것은 쉽지 않으니.. 앞으로 해당 확장자를 잘 활용해서 Next.js가 페이지 파일을 잘 구분할 수 있도록 해야 할 것 같습니다.</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://nextjs.org/docs/pages/api-reference/next-config-js/pageExtensions">https://nextjs.org/docs/pages/api-reference/next-config-js/pageExtensions</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[나만의 eslint-config 만들기 (실전편) (feat. airbnb)]]></title>
            <link>https://velog.io/@s_sangs/%EB%82%98%EB%A7%8C%EC%9D%98-eslint-config-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%8B%A4%EC%A0%84%ED%8E%B8-feat.-airbnb</link>
            <guid>https://velog.io/@s_sangs/%EB%82%98%EB%A7%8C%EC%9D%98-eslint-config-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%8B%A4%EC%A0%84%ED%8E%B8-feat.-airbnb</guid>
            <pubDate>Mon, 08 May 2023 00:41:03 GMT</pubDate>
            <description><![CDATA[<p>이전에 나만의 <code>eslint-config</code> 만들기 (이론편)을 포스팅했는데요!</p>
<p>사실 이론편이라기 보다는 ESLint의 공식문서의 일부를 번역한 내용입니다!
실제로 <code>eslint-config</code>를 만들기 위해서는 더 다양한 부분을 이해할 수 있어야할 것 같습니다.
다른 <code>eslint-config</code>나 <code>eslint-plugin</code>을 가져와서 사용하는 부분에 대한 설명도 없고, 어떻게 만들 수 있는지에 초점을 두는 문서이기 때문이죠.</p>
<p>그래도 기본적으로 <code>eslint-config</code>를 만들기 위한 최소 규칙? 정도라고 이해해주시면 될 것 같습니다.</p>
<p>오늘은 많은 분들이 사용하시는 <code>airbnb</code> 관련 <code>plugin</code>과 <code>config</code>를 이용해서 나만의 <code>eslint-config</code>를 만들어보려고 합니다!
개인적으로 <code>React</code>, <code>Next</code>, <code>React Native</code>와 관련된 프로젝트를 주로 진행하기 때문에 <code>airbnb</code> 컨벤션을 선호합니다.</p>
<p>너무 깊게 ESLint를 설정하지 않는다면, 이정도의 설정으로도 충분히 ESLint를 잘 활용할 수 있다고 생각합니다.</p>
<blockquote>
<p>만약 본인이 ESLint의 <code>plugin</code>, <code>config</code>의 차이, <code>extends</code>, <code>rule</code>, <code>recommended</code>와 같은 키워드를 모르신다면, 정말 리얼 마지막 ESLint 사용법 뿌시기 포스팅을 한 번 보시고 오시는 것을 추천드립니다. 🙏</p>
</blockquote>
<h2 id="프로젝트-세팅">프로젝트 세팅</h2>
<pre><code class="language-bash">mkdir eslint-config-mytool
cd eslint-config-mytool
yarn init</code></pre>
<pre><code class="language-json">// package.json
{
  &quot;name&quot;: &quot;eslint-config-mytool&quot;,
  &quot;version&quot;: &quot;0.1.0&quot;,
  &quot;description&quot;: &quot;My ESLint Custom Config&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;license&quot;: &quot;MIT&quot;
}</code></pre>
<p>명령어를 따라가다 보면 위와같은 <code>package.json</code> 파일이 생성되게 됩니다.</p>
<blockquote>
<p>라이브러리 이름은 <code>eslint-config</code>가 포함되어야 합니다.
이름에 대한 규칙은 ESLint에서 정한 규칙입니다.</p>
</blockquote>
<h2 id="라이브러리-만들기">라이브러리 만들기</h2>
<p><code>eslint-config</code> 라이브러리를 만드는 방식은 한 가지만 있는 것은 아닙니다.
오늘 사용하는 방법은 여러 방법 중 하나라고 생각해주시면 감사하겠습니다. 🙏</p>
<p><code>airbnb</code>의 <code>eslint-config</code> 라이브러리는 크게 <code>eslint-config-airbnb</code>, <code>eslint-config-airbnb-base</code>로 나뉩니다!
<code>javascript</code>만 사용한다면, <code>eslint-config-airbnb-base</code>를 사용하는 것을 권장합니다.
<br></p>
<h3 id="airbnb-base-설정"><code>airbnb-base</code> 설정</h3>
<p><code>import</code>, <code>es6</code>, <code>node</code>, <code>variables</code>와 같은 설정이 포함되어 있습니다.</p>
<h4 id="라이브러리-설치">라이브러리 설치</h4>
<pre><code class="language-bash">yarn add --dev eslint eslint-config-airbnb-base</code></pre>
<h4 id="indexjs-파일-작성"><code>index.js</code> 파일 작성</h4>
<pre><code class="language-js">// index.js
module.exports = {  
  env: {  
    es2021: true,  
    node: true,  
    browser: true,  
  },  
  extends: [&quot;eslint:recommended&quot;, &quot;airbnb-base&quot;],  
  parserOptions: {  
    ecmaVersion: 12,  
    sourceType: &quot;module&quot;,  
  },  
  rules: {  
    // custom rules  
  }  
};</code></pre>
<p>위와 같이 설정하면 <code>eslint-config-mytool</code> 라이브러리는 <code>eslint-config-airbnb-base</code>와 동일한 역할을 하는 라이브러리가 됐습니다!
<br></p>
<h3 id="react-설정"><code>react</code> 설정</h3>
<p>여기서 <code>react</code>와 관련된 설정을 추가하려면 어떻게 해야할까요?</p>
<h4 id="라이브러리-설치-1">라이브러리 설치</h4>
<pre><code class="language-bash">yarn add --dev eslint-config-airbnb \
               eslint-plugin-import \
               eslint-plugin-jsx-a11y \
               eslint-plugin-react \
               eslint-plugin-react-hooks</code></pre>
<p><code>eslint-config-airbnb</code> 이후의 설치되는 라이브러리들은 모두 <code>eslint-config-airbnb</code>에서 필요한 의존성들입니다.
<code>eslint-config-airbnb</code>만 설치했을 때 <code>react</code>와 관련된 설정을 사용할 수 없습니다.</p>
<h4 id="reactjs-파일-작성"><code>react.js</code> 파일 작성</h4>
<pre><code class="language-js">module.exports = {  
  extends: [&quot;plugin:react/recommended&quot;, &quot;airbnb&quot;, &quot;airbnb/hooks&quot;],  
  plugins: [&quot;react&quot;],  
  parserOptions: {  
    ecmaFeatures: {  
      jsx: true,  
    },  
  },  
  rules: {  
    // custom rules  
  },  
};</code></pre>
<p>위와 같이 작성하면 <code>react</code>와 관련된 설정도 추가해서 사용할 수 있습니다.
<br></p>
<h3 id="typescript-설정"><code>typescript</code> 설정</h3>
<h4 id="라이브러리-설치-2">라이브러리 설치</h4>
<pre><code class="language-bash">yarn add -dev eslint-config-airbnb-typescript \
              @typescript-eslint/eslint-plugin \
              @typescript-eslint/parser</code></pre>
<h4 id="typescriptjs-파일-작성"><code>typescript.js</code> 파일 작성</h4>
<pre><code class="language-js">module.exports = {  
  parser: &quot;@typescript-eslint/parser&quot;,  
  parserOptions: {  
    project: [&quot;./tsconfig.json&quot;],  
  },  
  plugins: [&quot;@typescript-eslint&quot;],  
  extends: [  
    &quot;plugin:@typescript-eslint/eslint-recommended&quot;,  
    // airbnb-typescript
    &quot;airbnb-typescript/base&quot;,
    // airbnb-typescript + react
    &quot;airbnb-typescript&quot;,  
  ],  
};</code></pre>
<p><code>eslint-config-airbnb-base</code>와 같이 <code>react</code> 설정을 포함하지 않아도 될 때는 <code>extends</code>에서 <code>airbnb-typescript/base</code>로 설정을 추가하면 됩니다.</p>
<blockquote>
<p>별도의 파일을 생성하지 않고 <code>index.js</code> 파일에 위의 모든 설정을 한 번에 넣어도 상관없습니다.
크게 확장성을 고려하지 않는다면, <code>index.js</code> 파일에서 한 번에 관리하는 것도 좋아보입니다. 👍
<br></p>
</blockquote>
<h2 id="packagejson-파일-및-디렉터리-구조"><code>package.json</code> 파일 및 디렉터리 구조</h2>
<pre><code class="language-json">{  
  &quot;name&quot;: &quot;eslint-config-mytool&quot;,  
  &quot;version&quot;: &quot;0.1.0&quot;,  
  &quot;description&quot;: &quot;My ESLint Custom Config&quot;,  
  &quot;main&quot;: &quot;index.js&quot;,  
  &quot;license&quot;: &quot;MIT&quot;,  
  &quot;dependencies&quot;: {  
    &quot;eslint-config-airbnb-base&quot;: &quot;^15.0.0&quot;,  
    &quot;eslint-config-airbnb&quot;: &quot;^19.0.4&quot;,  
    &quot;eslint-config-airbnb-typescript&quot;: &quot;^17.0.0&quot;  
  },  
  &quot;devDependencies&quot;: {  
    &quot;@typescript-eslint/eslint-plugin&quot;: &quot;^5.59.2&quot;,  
    &quot;@typescript-eslint/parser&quot;: &quot;^5.59.2&quot;,  
    &quot;eslint&quot;: &quot;^8.40.0&quot;,  
    &quot;eslint-config-airbnb&quot;: &quot;^19.0.4&quot;,  
    &quot;eslint-config-airbnb-base&quot;: &quot;^15.0.0&quot;,  
    &quot;eslint-config-airbnb-typescript&quot;: &quot;^17.0.0&quot;,  
    &quot;eslint-plugin-import&quot;: &quot;^2.27.5&quot;,  
    &quot;eslint-plugin-jsx-a11y&quot;: &quot;^6.7.1&quot;,  
    &quot;eslint-plugin-react&quot;: &quot;^7.32.2&quot;,  
    &quot;eslint-plugin-react-hooks&quot;: &quot;^4.6.0&quot;,  
    &quot;prettier&quot;: &quot;^2.8.8&quot;  
  },  
  &quot;peerDependencies&quot;: {  
    &quot;@typescript-eslint/eslint-plugin&quot;: &quot;^5.59.2&quot;,  
    &quot;@typescript-eslint/parser&quot;: &quot;^5.59.2&quot;,  
    &quot;eslint&quot;: &quot;^8.40.0&quot;,  
    &quot;eslint-plugin-import&quot;: &quot;^2.27.5&quot;,  
    &quot;eslint-plugin-jsx-a11y&quot;: &quot;^6.7.1&quot;,  
    &quot;eslint-plugin-react&quot;: &quot;^7.32.2&quot;,  
    &quot;eslint-plugin-react-hooks&quot;: &quot;^4.6.0&quot;  
  }  
}</code></pre>
<pre><code>eslint-config-mytool
├─ node_modules/
├─ index.js
├─ react.js
├─ typescript.js
└─ package.json</code></pre><blockquote>
<p>ESLint에서는 <code>peerDependencies</code>를 명시해주는 것을 권장합니다.
<code>eslint</code>와 플러그인의 버전마다 추가 된 규칙이나 옵션이 있기 때문에 설정한 규칙을 지원하는 버전을 명시해주는 것이 좋다고 합니다.</p>
</blockquote>
<h2 id="배포하기">배포하기</h2>
<pre><code class="language-bash">npm publish</code></pre>
<p>배포하기 전 어느정도의 과정이 필요합니다.
NPM 배포에 대한 내용은 생략하도록 하겠습니다.</p>
<h2 id="사용하기">사용하기</h2>
<pre><code class="language-bash">yarn add --peer --dev eslint-config-mytool
yarn add --dev eslint-config-mytool</code></pre>
<p><code>--peer</code> 명령어를 통해서 <code>eslint-config-mytool</code>에서 명시한 <code>peerDependency</code>를 같이 설치하게 됩니다.</p>
<h3 id="default"><code>default</code></h3>
<pre><code class="language-json">// .eslintrc.json
{  
  &quot;extends&quot;: [&quot;eslint-config-mytool&quot;],  
  &quot;rules&quot;: {  
    // custom rules  
  }  
}</code></pre>
<h3 id="react"><code>react</code></h3>
<pre><code class="language-json">{  
  &quot;extends&quot;: [&quot;eslint-config-mytool&quot;, &quot;eslint-config-mytool/react&quot;]  
}</code></pre>
<h3 id="typescript"><code>typescript</code></h3>
<pre><code class="language-json">{  
  &quot;extends&quot;: [&quot;eslint-config-mytool&quot;, &quot;eslint-config-mytool/typescript&quot;]  
}</code></pre>
<p>위와 같이 필요한 설정들을 <code>extends</code> 필드에 추가해서 사용하면 됩니다.
라이브러리에서 <code>custom rule</code>을 관리해도 되고 프로젝트의 <code>.eslintrc</code> 파일에서 <code>rules</code>를 관리하셔도 됩니다!</p>
<h2 id="마무리">마무리</h2>
<p>개인 프로젝트를 많이 하는 것은 아니지만, Lint에 관심이 생기다 보니 위와 같이 만들어보는 작업을 경험해서 좋았습니다! 🤩</p>
<p>회사에서는 개발하느라 바쁘고, 이 부분을 이정도까지 신경써야 하는가? 라는 생각도 했었는데요.
처음 개발을 시작할 때를 생각해보면 요즘 저는 꽤나 많이 협업과 도구에 대한 관심이 생긴 것 같습니다.😎
회사의 여러 프로젝트에 동일한 포맷팅과 컨벤션을 제공할 수 있다는 것은 꽤나 매력적인 것 같습니다. ㅎㅎ</p>
<p>처음에 이 작업을 할 때, ESLint의 룰도 하나씩 만져보면서 개인 혹은 조직에 맞는 라이브러리를 만들어보고 싶었습니다.
하지만 모든 룰들을 확인하면서 규칙들을 적용하는 것은 꽤나 많은 시간이 소요되는 일이었습니다. 😭</p>
<p>왜 사람들이 기존의 컨벤션으로 되어있는 것을 커스텀해서 사용하는지 알게 되었습니다. ㅎㅎ</p>
<p>차라리 이 시간에 해야할 것들과 하고 싶은 것들을 하는 것이 더 가치있다고 생각해서 제일 유명한 컨벤션 라이브러리를 참고해서 나만의 <code>eslint-config</code> 라이브러리를 만들어 보았습니다.</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base/rules">https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base/rules</a></li>
<li><a href="https://github.com/iamturns/eslint-config-airbnb-typescript">https://github.com/iamturns/eslint-config-airbnb-typescript</a></li>
<li><a href="https://github.com/ridi/eslint-config">https://github.com/ridi/eslint-config</a></li>
<li><a href="https://caferion.netlify.app/frontend/eslint-rule-setting/">https://caferion.netlify.app/frontend/eslint-rule-setting/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[나만의 eslint-config 만들기 (이론편)]]></title>
            <link>https://velog.io/@s_sangs/%EB%82%98%EB%A7%8C%EC%9D%98-eslint-config-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%9D%B4%EB%A1%A0%ED%8E%B8</link>
            <guid>https://velog.io/@s_sangs/%EB%82%98%EB%A7%8C%EC%9D%98-eslint-config-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%9D%B4%EB%A1%A0%ED%8E%B8</guid>
            <pubDate>Sun, 07 May 2023 23:39:54 GMT</pubDate>
            <description><![CDATA[<p><em>해당 포스팅은 eslint 공식 홈페이지를 번역한 내용입니다.</em></p>
<h2 id="공유-환경설정-share-configurations">공유 환경설정 (Share Configurations)</h2>
<p>ESLint Configuration을 공유하기 위해서는, <strong>공유 가능한 config</strong>를 만들어야 합니다.
공유 가능한 config를 NPM에 배포할 수 있으며, 다른 사용자들이 배포된 config를 다운로드하고 사용할 수 있습니다.</p>
<p><em>이 페이지는 어떻게 공유 가능한 config를 만들고 배포하는지 설명합니다.</em></p>
<h2 id="공유-가능한-config-생성-creating-a-shareable-config">공유 가능한 config 생성 (Creating a Shareable Config)</h2>
<p>공유 가능한 config는 환경설정 객체를 가져오는(export) 간단한 NPM 패키지입니다.
시작하기 앞서서, 평소처럼 Node.js 모듈을 만들어봅시다.</p>
<p>해당 모듈의 이름은 다음 중 하나의 양식을 따라야 합니다.</p>
<ul>
<li><code>eslint-config</code>로 시작해야 합니다. 예를 들면 <code>eslint-config-myconfig</code>로 작성할 수 있습니다.</li>
<li>npm scpoed 모듈입니다. scoped 모듈을 생성하려면, 모듈의 이름 또는 접두사를 <code>@scope/eslint-config</code>로 지정합니다.
 <code>@scope/eslint-config</code> 혹은 <code>@scope/eslint-config-myconfig</code> 처럼 사용할 수 있습니다.</li>
</ul>
<p>모듈 안에서, 공유 가능한 config에서 모듈의 메인 진입점 파일(main entry point file)을 가져옵니다. (export)
기본적으로 메인 진입점 포인트 파일은 <code>index.js</code> 파일입니다.</p>
<p>예를 들면</p>
<pre><code class="language-js">// index.js
module.exports = {

    globals: {
        MyGlobal: true
    },

    rules: {
        semi: [2, &quot;always&quot;]
    }

};</code></pre>
<p><code>index.js</code> 파일은 자바스크립트이기 때문에, 파일에서 이 설정들을 읽어올 수 있고 동적으로 생성할 수 있습니다.
<br></p>
<h2 id="공유-가능한-config-배포">공유 가능한 config 배포</h2>
<p>공유 가능한 config가 준비 되었을 때, 다른 사람과 공유할 수 있게 NPM에 배포할 수 있습니다. 
<code>package.json</code> 파일 안에 <code>eslint</code>, <code>eslintconfig</code>와 같은 <code>keywords</code>를 사용하는 것을 권고합니다.
다른 사용자들이 쉽게 해당 모듈을 찾을 수 있습니다.</p>
<p><code>package.json</code> 파일 안에 <code>peerDependencies</code> 필드를 이용해서 ESLint 의존성을 선언할 수 있습니다.
호환성을 고려하면서 의존성을 선언할 때 추천하는 방식은  <code>&gt;=</code>와 같은 범위 구문을 사용하는 것입니다.</p>
<p>예를 들면</p>
<pre><code class="language-json">{
    &quot;peerDependencies&quot;: {
        &quot;eslint&quot;: &quot;&gt;= 3&quot;
    }
}</code></pre>
<p>만약 공유 가능한 config가 어떠한 플러그인에 의존하고 있다면, 그것 또한 <code>peerDependency</code>로 지정해야 합니다.
(플러그인은 최종 사용자의 프로젝트에서 사용되는 것과 관련이 되어 있으므로, 최종 사용자는 필요한 플러그인을 설치해야 합니다.)</p>
<p>그러나, 만약 공유 가능한 config가 커스텀 parser에 의존하고 있거나 다른 공유 가능한 config에 의존하고 있다면 이러한 패키지들은 <code>package.json</code> 파일 안에 있는 <code>dependencies</code> 필드에 지정할 수 있습니다.</p>
<p>공유 가능한 config를 배포하기전에 컴퓨터에서 linking을 이용해서 테스트 해볼 수 있습니다.</p>
<pre><code class="language-bash">npm link</code></pre>
<br>

<p>그 다음에, 공유 가능한 config를 사용하려고 하는 프로젝트에서 명령어를 입력합니다.</p>
<pre><code class="language-bash">npm link eslint-config-myconfig</code></pre>
<p>직접 진행할 때는 <code>eslint-config-myconfig</code>를 모듈의 실제 이름으로 변경하세요.</p>
<br>

<h2 id="공유-가능한-config-사용">공유 가능한 config 사용</h2>
<p>공유 가능한 config를 사용할 때, 설정 파일의 <code>extends</code> 필드 안에 해당 config 이름을 포함해야 합니다.
모듈 이름을 작성합니다.</p>
<p>예를 들면</p>
<pre><code class="language-json">{
    &quot;extends&quot;: &quot;eslint-config-myconfig&quot;
}</code></pre>
<br>

<p><code>eslint-config</code>를 생략할 수 있습니다. 
ESLint에 의해 자동적으로 추정됩니다.</p>
<pre><code class="language-json">{
    &quot;extends&quot;: &quot;myconfig&quot;
}</code></pre>
<p>공유 가능한 config는 ESLint CLI --config 플래그와 같이 사용할 수 없습니다.</p>
<br>


<h2 id="npm-scoped-modules">NPM Scoped Modules</h2>
<p>NPM의 scoped 모듈 또한 여러 방식을 지원합니다.</p>
<p>모듈 이름을 사용할 수 있습니다.</p>
<pre><code class="language-json">{
    &quot;extends&quot;: &quot;@scope/eslint-config&quot;
}</code></pre>
<br>

<p><code>eslint-config</code>를 생략할 수 있습니다.</p>
<pre><code class="language-json">{
    &quot;extends&quot;: &quot;@scope&quot;
}</code></pre>
<br>


<p>모듈의 이름은 커스터마이징할 수 있습니다.
예를 들어서 패키지의 이름이 <code>@scope/eslint-config-myconfig</code>라면, 아래와 같이 명시할 수 있습니다.</p>
<pre><code class="language-json">{
    &quot;extends&quot;: &quot;@scope/eslint-config-myconfig&quot;
}</code></pre>
<br>

<p>또한 eslint-config를 생략할 수 있습니다.</p>
<pre><code class="language-json">{
    &quot;extends&quot;: &quot;@scope/myconfig&quot;
}</code></pre>
<br>

<h2 id="공유-가능한-config의-설정-오버라이딩">공유 가능한 config의 설정 오버라이딩</h2>
<p><code>.eslintrc</code> 파일을 통해서 공유 가능한 config의 설정들을 오버라이딩할 수 있습니다.</p>
<h2 id="여러-config-공유">여러 config 공유</h2>
<p>여러 config들을 하나의 NPM 패키지에서 공유할 수 있습니다.
공유 가능한 config 생성(Creating a Shareable Config) 섹션에 패키지의 기본 config가 명시되어 있습니다. NPM 패키지에 새로운 파일을 추가함으로써 추가적인 config를 명시할 수 있습니다. 그리고 추가한 config를 참조할 수 있습니다.</p>
<p>예를 들어서, NPM 패키지에 <code>my-sepcial-config.js</code>라고 불리는 파일을 생성할 수 있습니다.
그리고 해당 config도 export 할 수 있습니다.</p>
<pre><code class="language-js">// my-special-config.js
module.exports = {
    rules: {
        quotes: [2, &quot;double&quot;]
    }
};</code></pre>
<br>

<p>그리고 나서, 당신이 사용하고 있는 패키지 이름이 <code>eslint-config-myconfig</code>라고 가정했을 때
추가적인 config를 접근할 수 있습니다.</p>
<pre><code class="language-json">{
    &quot;extends&quot;: &quot;@scope/eslint-config/my-special-config&quot;
}</code></pre>
<p>파일 이름에서 <code>.js</code>을 분리해서 사용할 수 있습니다.</p>
<p><strong>중요!</strong>
에러를 방지하기 위해서 plugin 안에는 항상 default config를 포함하고 있는 것을 강력하게 권장합니다.</p>
<h2 id="local-config-file-resolution">Local Config File Resolution</h2>
<p>만약 각기 다른 디렉터리에 있는 config에 서로 확장이 가능한 config 생성이 필요하다면, 필요한 내용을 조작할 수 있는 하나의 공유 가능한 config를 만들 수 있습니다.</p>
<p>예를 들어서, 사용하는 패키지 이름을 <code>eslint-config-myconfig</code>라고 가정하고, 해당 패키지는 아래의 구조를 가지고 있습니다.</p>
<pre><code class="language-text">myconfig
├── index.js
└─┬ lib
  ├── defaults.js
  ├── dev.js
  ├── ci.js
  └─┬ ci
    ├── frontend.js
    ├── backend.js
    └── common.js</code></pre>
<br>

<p><code>index.js</code> 파일에서는 아래와 같이 config 파일을 export 할 수 있습니다.</p>
<pre><code class="language-js">module.exports = require(&#39;./lib/ci.js&#39;);</code></pre>
<br>

<p>패키지 안에는 아래와 같은 내용을 담고 있는 <code>/lib/defaults.js</code> 파일이 있습니다.</p>
<pre><code class="language-js">module.exports = {
    rules: {
        &#39;no-console&#39;: 1
    }
};</code></pre>
<br>

<p><code>/lib/ci.js</code> 파일 안에는</p>
<pre><code class="language-js">module.exports = require(&#39;./ci/backend&#39;);</code></pre>
<br>

<p><code>/lib/ci/common.js</code> 안에는</p>
<pre><code class="language-js">module.exports = {
    rules: {
        &#39;no-alert&#39;: 2
    },
    extends: &#39;myconfig/lib/defaults&#39;
};</code></pre>
<p>config 파일의 모든 <code>extends</code> 키워드에 확장하고 싶은 파일의 절대경로(<code>full package path</code>)를 사용함으로써 확장을 할 수 있습니다.
<br></p>
<h3 id=""></h3>
<p><code>/lib/ci/backend.js</code> 내용</p>
<pre><code class="language-js">module.exports = {
    rules: {
        &#39;no-console&#39;: 1
    },
    extends: &#39;myconfig/lib/ci/common&#39;
};</code></pre>
<p><code>/lib/ci/backend.js</code> 파일을 보면 config를 적절하게 사용하려면 패키지의 전체 경로를 포함해야 하는 것을 다시 한 번 확인할 수 있습니다.</p>
<h2 id="마무리">마무리</h2>
<p>새로운 라이브러리 혹은 프레임워크, 언어를 배우면서 공식문서를 제대로 번역해본적이 없었는데요!
최근 ESLint 내용을 계속해서 찾아보다보니, 공식문서를 한 번 번역해보고 싶다는 생각이 들었습니다! 📖</p>
<p>그래서 모든 문서를 다 번역하는 것은 어렵지만, 한 페이지 정도는 빠르게 할 수 있지 않을까? 라는 생각에 도전하게 되었습니다!
그래도 다른 포스팅과 문서들을 찾아보고 공식문서를 보니 어떠한 의미로 설명되었는지 조금 더 쉽게 이해가 됐던 것 같습니다!</p>
<p>그래도 언제나 그렇듯.. 영어는 어려운 것 같습니다 🤦‍♂️</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://eslint.org/docs/latest/extend/shareable-configs#creating-a-shareable-config">https://eslint.org/docs/latest/extend/shareable-configs#creating-a-shareable-config</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Husky & lint-staged 설정하기]]></title>
            <link>https://velog.io/@s_sangs/Husky-lint-staged</link>
            <guid>https://velog.io/@s_sangs/Husky-lint-staged</guid>
            <pubDate>Sun, 07 May 2023 12:52:28 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-해결하기">문제 해결하기</h2>
<p>이전에 <code>@typescript-eslint</code>와 <code>prettier</code>를 설정한 적이 있습니다.
<code>prettier</code>는 코드 포맷팅을 하기 위한 라이브러리이기 때문에 크게 설정할 내용이 없었는데요.
<code>eslint</code>의 경우에는 문제가 있었습니다.</p>
<h3 id="eslint를-강하게-사용할-수-없다-💪">eslint를 강하게 사용할 수 없다 💪</h3>
<p>저는 기존에 <code>CRA</code>을 이용해서 프로젝트를 생성했었습니다.</p>
<p>기본적으로 <code>typescript</code>도 사용하고 있었습니다.
<code>CRA</code>로 생성하게 되면 프로젝트를 실행, 수정할 때마다 컴파일이 새롭게 되고 lint 검사도 같이 진행하게 됩니다.</p>
<p>그런데 만약 <code>eslint</code> 설정에서 <code>no-console</code>을 <code>error</code>로 정의하게 되면 어떨까요?
콘솔을 찍어보기 위해서 작성한 <code>console.log()</code> 명령어를 <code>error</code>가 됩니다.</p>
<p>그렇다고 <code>no-console</code>을 <code>error</code>로 정의하지 않고 그대로 사용한다면, 배포했을 때 <code>console.log()</code> 명령어가 배포된 프로젝트에 반영될 수 있는 상황을 나올 수 있습니다.</p>
<p>결국 어떠한 조치를 하지 않으면, <code>eslint</code>를 제대로 활용하고 있지 않다라는 생각이 들었습니다.</p>
<blockquote>
<p>혹시 위의 내용을 더 쉽게 풀어나갈 수 있는 방법이 있다면 공유해주시면 감사하겠습니다 🙏</p>
</blockquote>
<h3 id="그렇다면lint-검사를-하지-않는다">그렇다면lint 검사를 하지 않는다.</h3>
<p><code>CRA</code>에서 제공하는 <code>eslint</code> 검사를 자동으로 하지 않게 설정하는 것입니다.
그리고 <code>git hook</code>을 이용해서 특정 시점에 lint 검사를 할 수 있도록 하는 것이죠!</p>
<p>저는 <code>craco</code> 라이브러리를 사용하고 있기 때문에 <code>craco.config.js</code> 파일을 수정했습니다.
아래와 같이 <code>enable</code>을 <code>false</code>로 설정하면 자동으로 lint 검사하는 설정을 끌 수 있습니다.</p>
<pre><code class="language-javascript">module.exports = {
    eslint: {
        enable: false,
    }
}</code></pre>
<h3 id="eslint-룰-수정하기-✏️"><code>eslint</code> 룰 수정하기 ✏️</h3>
<p>모든 <code>eslint</code> 룰을 다 나열할 수는 없지만, <code>no-console</code>, <code>no-empty</code> 와 같이 불필요한 코드를 사용하지 않게 해주는 룰을 추가했습니다.</p>
<p>다양한 룰들을 설정할 수 있으니 <code>@typescript-eslint</code>, <code>eslint</code> 페이지에 들어가셔서 본인에게 맞는 룰들을 추가하면 좋을 것 같습니다.</p>
<h3 id="git-hook을-통한-lint-검사"><code>git hook</code>을 통한 lint 검사</h3>
<p>이미 <code>git</code>은 특정 상황에서 스크립트를 실행할 수 있도록 <code>hook</code>이라는 기능을 지원하고 있습니다!
별도로 설치할 필요도 없고, <code>git</code>으로 관리되고 있는 폴더에서 <code>cd .git/hooks/</code> 명령어를 입력하고 <code>ls</code> 명령어를 입력하면 <code>git</code>이 제공하는 특정 상황을 볼 수 있습니다.</p>
<p>하지만 아쉽게도 <code>git hook</code>은 원격으로 저장하고 관리할 수 없습니다.
그래서 <code>git hook</code>을 공유하기 위한 여러가지 방법들이 나왔는데 저는 그 중 <code>husky</code>를 사용해보고자 했습니다.</p>
<h2 id="husky-도입-🐶">Husky 도입 🐶</h2>
<h3 id="husky">Husky</h3>
<ul>
<li><code>git hook</code>에 따라 원하는 동작을 하게 도와주는 패키지</li>
<li><code>git hook</code>에 대한 정책을 관리하고 공유할 수 있다.</li>
<li><code>git add</code>나 <code>commit</code>, <code>push</code>가 시행되기 전이나 후 등 여러 조건에 원하는 스크립트를 실행시켜준다.</li>
</ul>
<h3 id="husky-설치">husky 설치</h3>
<pre><code class="language-bash">yarn add --dev husky</code></pre>
<br>


<h3 id="packagejson에-코드-작성"><code>package.json</code>에 코드 작성</h3>
<pre><code class="language-json">&quot;scripts&quot;: {
    &quot;prepare&quot;: &quot;husky install&quot;
}</code></pre>
<br>


<h3 id="husky-폴더-생성">husky 폴더 생성</h3>
<p>명령어를 실행하고 나면 <code>.husky</code> 폴더가 생성됩니다.</p>
<pre><code class="language-bash">yarn prepare</code></pre>
<blockquote>
<p>해당 폴더에서 스크립트 파일을 추가할 수 있습니다.</p>
</blockquote>
<br>



<h3 id="특정-이벤트에-실행할-스크립트-추가-pre-commit">특정 이벤트에 실행할 스크립트 추가 (<code>pre-commit</code>)</h3>
<p>해당 스크립트를 추가하면 <code>.husky</code> 폴더 안에 <code>pre-commit</code> 파일이 생성됩니다.
<code>husky</code>에서 제공하는 다양한 시점이 있지만, 대부분 <code>pre-commit</code>을 사용하는 것 같았습니다.
lint 검사 뿐만 아니라 테스트를 진행할 수도 있으니 다양한 부분에서 활용이 가능합니다.</p>
<pre><code class="language-bash">npx husky add .husky/pre-commit &#39;yarn init&#39;</code></pre>
<blockquote>
<p>추후에 <code>&#39;yarn init&#39;</code>과 같은 명령어가 수정되면 해당 파일 안에서 수정하면 됩니다.
commit 전에 <code>&#39;yarn init&#39;</code> 명령어를 실행하는 코드입니다.</p>
</blockquote>
<br>


<h2 id="lint-staged-⚙️">lint-staged ⚙️</h2>
<p><code>lint-staged</code>는 <code>git</code>에서 <code>stage</code> 단계에 있는 파일들만 검사해주는 라이브러리입니다.</p>
<p>위와 같이 작업을 하다보니 제가 작업한 파일만 lint 검사를 하는 것이 아니라, 모든 프로젝트 파일에 대해서 lint 검사를 진행하게 됐습니다.
제가 작업한 파일에 대해서만 검사를 해줄 수 있는 도구가 필요했습니다.</p>
<h3 id="lint-staged-설치"><code>lint-staged</code> 설치</h3>
<pre><code class="language-bash">yarn add --dev lint-staged</code></pre>
<br>


<h3 id="packagejson에-코드-작성-1"><code>package.json</code>에 코드 작성</h3>
<pre><code class="language-json">&quot;scripts&quot;: {
    &quot;lint-staged&quot;: &quot;lint-staged&quot;
}
&quot;lint-staged&quot;: {
    &quot;src/**&quot;: [
        &quot;eslint&quot;
    ]
}</code></pre>
<h3 id="pre-commit-파일-수정"><code>pre-commit</code> 파일 수정</h3>
<pre><code>yarn init --&gt; yarn lint-staged</code></pre><h2 id="마무리">마무리</h2>
<p>위의 내용들은 <code>eslint</code>가 설정이 되어 있는 가정이 있습니다.</p>
<p><code>husky</code>와 <code>lint-staged</code>를 적용했기 때문에, 앞으로는 디버그할 때는 자유롭게 코드를 작성해서 사용할 수 있습니다! 👏
협업하기 위해서 <code>git</code>을 사용하는 순간에는 lint 검사를 진행하게 될 것입니다.</p>
<p><code>prettier write</code> 같은 작업도 같이 할 수 있고 테스트 코드에 대한 테스트도 진행할 수 있습니다.
코드 퀄리티도 더 보장이 잘 될 것이고, 코딩 컨벤션도 잘 지킬 수 있게 되겠죠!
개인적으로 <code>Husky</code>와 <code>lint-staged</code>의 적용은 너무 만족하고 있습니다!</p>
<h3 id="아직-해결하지-못한-🤦♂️">아직 해결하지 못한.. 🤦‍♂️</h3>
<p><code>eslint</code> 검사를 진행할 때 <code>warning</code>만 나온다면, <code>warning</code>에 대한 표시는 해주지 않고 통과됩니다..
<code>warning</code>을 띄워주고 <code>commit</code>이 되야할 것 같은데 말이죠..</p>
<p>그래서 <code>error</code>가 있을 때만 같이 보여주고 이후의 작업이 멈춥니다.
이 부분은 조금 더 확인을 해봐야될 것 같습니다!</p>
<h3 id="혹시나-sourcetree를-사용한다면-🌲">혹시나 sourceTree를 사용한다면 🌲</h3>
<p><code>yarn</code>을 찾을 수 없다는 메시지가 계속 나와서 한참을 헤맸습니다..
맥에서 node와 관련된 경로 이슈로 나와 있는데.. 저는 다른 방향으로 해결이 됐습니다!</p>
<p>기존에 <code>pre-commit</code>에 작성된 <code>yarn</code>을 <code>npx</code>로 변경했더니 문제가 해결됐습니다.. ㅎ
이후에는 <code>sourceTree</code>와 <code>Intellij</code>와 같은 <code>IDE</code>에서도 제대로 동작이 됐습니다.</p>
<p>기본적으로 <code>IDE</code> 터미널에서 해당 내용을 파악하는 것이 개인적으로 제일 편했습니다.
해당 소스코드를 바로 찾아갈 수 있다는 장점이 제일 큰 것 같습니다!</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://ms3864.tistory.com/412">https://ms3864.tistory.com/412</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[마크업 코딩 컨벤션 (Markup Coding Convention)]]></title>
            <link>https://velog.io/@s_sangs/%EB%A7%88%ED%81%AC%EC%97%85-%EC%BD%94%EB%94%A9-%EC%BB%A8%EB%B2%A4%EC%85%98-Markup-Coding-Convention</link>
            <guid>https://velog.io/@s_sangs/%EB%A7%88%ED%81%AC%EC%97%85-%EC%BD%94%EB%94%A9-%EC%BB%A8%EB%B2%A4%EC%85%98-Markup-Coding-Convention</guid>
            <pubDate>Fri, 05 May 2023 04:19:59 GMT</pubDate>
            <description><![CDATA[<h2 id="코딩-컨벤션이란-🤔">코딩 컨벤션이란? 🤔</h2>
<p><em>읽고, 관리하기 쉬운 코드를 작성하기 위한 일종의 코딩 스타일 규약</em>
<em>린터를 사용한다는 가정하에 린터로 검출할 수 없는 모호한 부분을 가이드</em></p>
<p>이번에 회사에서 마크업 코딩 컨벤션 관련해서 정리하게 될 기회가 생겼습니다.
여러 포스팅들을 찾아보고 저희한테 맞는 코딩 컨벤션을 작성하기 위해서 자료를 정리해봤는데요.
회사에서는 웹앱으로 서비스가 제공되고 있어서 보편적인 웹서비스에 적용할 수 있는 마크업 코딩 컨벤션보다는 내용이 적습니다.</p>
<p>추가적으로 CSS에 대한 코딩 컨벤션은 작성하지 않았고, <code>Naming Rule</code> 에는 파스칼 케이스, 카멜 케이스, 케밥 케이스, 스네이크 케이스 등 다양한 케이스에 대한 내용을 작성하지는 않았습니다.
스네이크 케이스로 작성하기로 결정된 상태여서 스네이크 케이스를 기준으로 작성합니다.</p>
<h2 id="🧑💻-마크업-컨벤션의-필요성">🧑‍💻 마크업 컨벤션의 필요성</h2>
<p>마크업 개발은 디자인, 브라우저, 스크립트, 성능, 접근성 등과 긴밀한 관계가 있습니다.
또한, 유지보수에 투자되는 비용을 최소화하기 위해 통일된 코드 작성법을 제시합니다.</p>
<p>개발을 하면서 코드를 최초로 작성한 사람이 끝까지 유지보수할 확률은 매우 낮습니다.
따라서, 최초 개발자가 아닌 사람도 코드를 빠르고 정확하게 이해할 수 있도록 작성하는 것은 코드의 유지보수 비용을 절감하고 업무 효율을 높이는데 결정적인 역할을 합니다.</p>
<p><strong><em>어떤 코딩 컨벤션을 선택하는 것이 중요한 것이 아니라, 통일된 기준으로 소스 코드를 작성하는 것이 중요합니다.</em></strong></p>
<h2 id="📚-용어-정리">📚 용어 정리</h2>
<p>컨벤션에 자주 사용되는 용어의 정의를 설명합니다.</p>
<h3 id="엘리먼트-element">엘리먼트 (Element)</h3>
<p>HTML 문서를 구성하는 요소(태그)를 의미합니다.</p>
<h3 id="애트리뷰트-attribute">애트리뷰트 (Attribute)</h3>
<p>엘리먼트에 부여할 수 있는 특성을 의미합니다.</p>
<h3 id="선택자-selector">선택자 (Selector)</h3>
<p>엘리먼트를 식별할 수 있는 이름을 의미합니다.</p>
<p>요소에 CSS 스타일을 적용하기 위한 패턴입니다.</p>
<h3 id="컴포넌트-component">컴포넌트 (Component)</h3>
<p>하나 이상의 기능 또는 역할을 가진 컨텐츠 단위의 UI 구성 요소를 의미합니다.</p>
<h2 id="syntax">Syntax</h2>
<ul>
<li>들여쓰기는 2개의 공백 문자(소프트탭)을 사용합니다.</li>
<li>모든 엘리먼트 명과 애트리뷰트 명은 스네이크 표기법(<code>Snake Case</code>)로 작성합니다.</li>
<li>모든 애트리뷰트 값은 큰 따옴표(<code>&quot;&quot;</code>)를 사용합니다.</li>
<li>닫는 태그가 선택적이어도 생략하지 않습니다. (ex: <code>&lt;/li&gt;</code>, <code>&lt;/body&gt;</code>)</li>
<li>빈 줄은 1줄을 초과하지 않습니다.</li>
<li><code>EditorConfig</code> 사용을 권장합니다.</li>
</ul>
<blockquote>
<p><code>EditorConfig</code>
환경(Editor, OS, file encoding)에 따라 코딩 스타일의 일관성이 깨지는 문제를 해결하기 위한 표준
character encoding, 개행 처리 방법, 들여쓰기 방법(tab or space) 등을 정의</p>
</blockquote>
<h2 id="doctype"><code>Doctype</code></h2>
<p>HTML5 DTD(Document Type Definition)로 선언합니다.
추가적으로 자기 마침 태그 (Self-Closing Tags)에 후행 슬래시(<code>/</code>)를 사용하지 않습니다.</p>
<pre><code class="language-HTML">&lt;!-- Bad --&gt;
&lt;input /&gt;
&lt;br /&gt;

&lt;!-- Good --&gt;
&lt;input&gt;
&lt;br&gt;</code></pre>
<br>

<h2 id="naming-rule"><code>Naming Rule</code></h2>
<ul>
<li>이름은 영문 소문자, 숫자, 언더스코어(<code>_</code>)로 작성합니다.</li>
<li>시작 이름은 영문 소문자로만 시작할 수 있습니다.</li>
<li>언더스코어는 단어와 단어를 조합할 때만 사용합니다.</li>
<li>언더스코어가 포함된 약속어는 숫자, 영문 소문자와 조합하여 사용할 수 있습니다.</li>
</ul>
<table>
<thead>
<tr>
<th>기본형</th>
<th>잘못된 예</th>
<th>올바른 예</th>
</tr>
</thead>
<tbody><tr>
<td>section</td>
<td>sectionList</td>
<td>section_list</td>
</tr>
</tbody></table>
<h3 id="id-class-naming-rule"><code>id</code>, <code>class</code> Naming Rule</h3>
<ul>
<li><code>id</code>는 문서 전체의 고유 식별자 이므로 한 문서에서 동일한 <code>id</code>를 여러 번 사용하지 않습니다.</li>
<li>레이아웃을 제외한 <code>id</code>는 스타일을 지정하지 않습니다.</li>
<li><code>class</code>는 문서에서 여러 번 사용할 수 있습니다.</li>
</ul>
<h2 id="html-코드-작성-규칙">HTML 코드 작성 규칙</h2>
<h3 id="w3c-validation">W3C Validation</h3>
<ul>
<li>HTML은 DTD의 명세에 맞게 작성하며, W3C Validation을 통과해야 합니다.</li>
<li>DTD를 제외한 모든 엘리먼트와 애트리뷰트는 소문자로 작성합니다.</li>
</ul>
<pre><code class="language-HTML">&lt;!-- Bad --&gt;
&lt;SPAN Class=&quot;desc&quot;&gt;간단한 설명&lt;/SPAN&gt;

&lt;!-- Good --&gt;
&lt;span class=&quot;desc&quot;&gt;간단한 설명&lt;/span&gt;</code></pre>
<br>


<h2 id="html-애트리뷰트-작성-규칙">HTML 애트리뷰트 작성 규칙</h2>
<h3 id="기본-규칙">기본 규칙</h3>
<ul>
<li>엘리먼트에서 <code>class</code>, <code>style</code>을 선언할 때는 선언 순서를 준수합니다.</li>
<li><code>class</code>, <code>style</code>을 선언할 때는 제일 뒷부분에 선언합니다.</li>
<li>애트리뷰트의 순서가 비슷한 엘리먼트끼리 통일되므로 검색하기 편해집니다.</li>
</ul>
<pre><code class="language-HTML">&lt;!-- Good --&gt;
&lt;input type=&quot;text&quot; id=&quot;user_id&quot; title=&quot;사용자&quot; class=&quot;input_txt&quot; style=&quot;width:100px&quot;&gt;</code></pre>
<br>

<h4 id="선언-순서">선언 순서</h4>
<blockquote>
<p><code>type</code> = <code>src</code> &gt; <code>id</code> = <code>title</code> = <code>name</code> &gt; <code>class</code> &gt; <code>style</code></p>
</blockquote>
<h3 id="boolean-애트리뷰트"><code>Boolean</code> 애트리뷰트</h3>
<ul>
<li>HTML5에서는 <code>Boolean</code> 애트리뷰트를 선언하는 것만으로도 <code>true</code> 값을 가집니다.</li>
<li>필요하지 않다면 <code>Boolean</code> 값을 작성하지 않습니다.</li>
</ul>
<pre><code class="language-HTML">&lt;!-- Not Bad --&gt;
&lt;button disabled=&quot;true&quot;&gt;&lt;/button&gt;

&lt;!-- Good --&gt;
&lt;button disabled&gt;&lt;/button&gt;</code></pre>
<br>


<h3 id="name-애트리뷰트"><code>name</code> 애트리뷰트</h3>
<ul>
<li><code>name</code> 애트리뷰트 값은 비즈니스 로직을 작성하는 언어의 Naming Rule에 맞게 작성하는 것을 권장합니다.</li>
<li>저희는 <code>Snake Case</code>를 사용하고 있기 때문에 동일한 Naming Rule을 사용하면 됩니다.</li>
</ul>
<pre><code class="language-HTML">&lt;!-- Snake Case --&gt;
&lt;form class=&quot;form&quot; id=&quot;my_form&quot; name=&quot;my_form&quot;&gt;
    &lt;input class=&quot;input&quot; type=&quot;text&quot; id=&quot;my_user_name&quot; name=&quot;my_user_name&quot;&gt;
&lt;/form&gt;</code></pre>
<br>


<h2 id="html-엘리먼트-작성-규칙">HTML 엘리먼트 작성 규칙</h2>
<h3 id="input"><code>&lt;input&gt;</code></h3>
<ul>
<li><code>label</code> 요소, <code>title</code> 애트리뷰트, <code>alt</code> 애트리뷰트를 통해 스크린 리더 사용자는 주변 맥락에 대한 이해 없이 각 요소에 독립적으로 접근해도 폼을 이해할 수 있습니다.</li>
</ul>
<h4 id="type이-text인-경우">type이 text인 경우</h4>
<ul>
<li>동일한 스타일의 텍스트 필드나 너비 값이 다를 경우 <code>style</code> 애트리뷰트를 이용해서 <code>width</code> 값을 제어합니다.</li>
<li>이렇게 하면 불필요한 클래스 생성을 막을 수 있습니다.</li>
</ul>
<pre><code class="language-HTML">&lt;!-- Bad --&gt;
&lt;input type=&quot;text&quot; class=&quot;input input--width-120&quot;&gt;
&lt;input type=&quot;text&quot; class=&quot;input input--width-180&quot;&gt;

&lt;!-- Good --&gt;
&lt;input type=&quot;text&quot; class=&quot;input&quot; style=&quot;width:120px&quot;&gt;
&lt;input type=&quot;text&quot; class=&quot;input&quot; style=&quot;width:180px&quot;&gt;</code></pre>
<br>


<h4 id="type이-radio-checkbox인-경우">type이 radio, checkbox인 경우</h4>
<ul>
<li>그룹핑이 필요하면 선택적으로 <code>name</code> 애트리뷰트를 이용하여 항목들을 그룹핑합니다.</li>
</ul>
<h4 id="type이-image인-경우">type이 image인 경우</h4>
<ul>
<li><code>alt</code> 애트리뷰트를 반드시 선언합니다.</li>
</ul>
<h3 id="label"><code>&lt;label&gt;</code></h3>
<ul>
<li><code>&lt;input&gt;</code>, <code>&lt;select&gt;</code>, <code>&lt;textarea&gt;</code>와 같은 폼 요소는 <code>for</code> 애트리뷰트를 부여하여 해당 요소의 <code>id</code> 값과 동일한 이름으로 연결(coupling)합니다.</li>
<li>단 레이블 명이 위치할 공간이 없는 경우 <code>title</code> 애트리뷰트로 대체할 수 있습니다.</li>
<li><code>&lt;label&gt;</code> 안에 <code>&lt;input&gt;</code> 엘리먼트가 있는 경우에는 <code>for</code>와 <code>id</code>를 이용하여 연결하지 않아도 됩니다.</li>
</ul>
<pre><code class="language-HTML">&lt;!-- for, id를 이용한 커플링 --&gt;
&lt;input type=&quot;radio&quot; name=&quot;alignment&quot; id=&quot;align_left&quot;&gt;
&lt;label for=&quot;align_left&quot;&gt;왼쪽 정렬&lt;/label&gt;

&lt;!-- &lt;label&gt;안에 &lt;input&gt; 엘리먼트가 있는 경우 --&gt;
&lt;label&gt;&lt;input type=&quot;checkbox&quot; name=&quot;sports&quot;&gt;축구&lt;/label&gt;</code></pre>
<br>


<h3 id="img"><code>&lt;img&gt;</code></h3>
<ul>
<li><code>src</code>, <code>width</code>, <code>height</code>, <code>title</code>, <code>alt</code>, <code>usemap</code> 애트리뷰트를 선택적으로 선언합니다.</li>
<li><code>src</code>, <code>alt</code> 애트리뷰트에 <code>import</code>한 이름과 동일한 값을 표기합니다.</li>
<li>이미지를 볼 수 없는 환경(스크린 리더, 이미지 서버 장애, 이미지를 표시하지 않음 설정)에서도 내용을 확인할 수 있게 합니다.</li>
<li><code>title</code> 애트리뷰트를 선언한 경우에도 <code>alt</code> 애트리뷰트를 함께 선언합니다.</li>
<li><code>title</code> 애트리뷰트는 브라우저에서 독립적으로 툴팁을 표현하기 위해서 사용합니다.</li>
</ul>
<pre><code class="language-HTML">&lt;!-- import, src, alt 애트리뷰트 --&gt;
import FinanceBanner from &#39;../../banner01.jpg&#39;

&lt;img src={FinanceBanner} alt=&quot;FinanceBanner&quot;&gt;

&lt;!-- 애트리뷰트 사용 예시 --&gt;
&lt;img src={FinanceBanner} width=&quot;30&quot; height=&quot;10&quot; title=&quot;배너&quot; alt=&quot;배너&quot; usemap=&quot;#help&quot;&gt;</code></pre>
<br>

<p>NHN 코딩 컨벤션이나 다른 코딩 컨벤션을 확인해보면 더욱 자세한 컨벤션 내용을 확인할 수 있습니다. 🔎</p>
<p>누군가 이 내용을 봤을 때 컨벤션으로 많이 부족하다고 생각할 수 있습니다.
해당 내용을 다 적용하면 좋지만, 어떤 코딩 컨벤션을 선택하는 것이 중요한 게 아니라 우리에게 필요한 통일된 기준이 필요했습니다.
그러한 기준으로 봤을 때 현재 작성된 내용은 개인적으로 만족스럽습니다</p>
<p>혹시나 코딩 컨벤션을 정해야 하는 상황이라면 현재 가지고 있는 익숙함에 필요한 컨벤션을 추가하면서 코딩 컨벤션을 만들어가면 좋을 것 같습니다. 💪</p>
<h2 id="출처">출처</h2>
<ul>
<li>NHN 코딩 컨벤션</li>
<li><a href="https://github.com/choegyumin/markup-coding-conventions">https://github.com/choegyumin/markup-coding-conventions</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[릴리즈 노트(Release Note)를 작성해보자]]></title>
            <link>https://velog.io/@s_sangs/%EB%A6%B4%EB%A6%AC%EC%A6%88-%EB%85%B8%ED%8A%B8Release-Note%EB%A5%BC-%EC%9E%91%EC%84%B1%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@s_sangs/%EB%A6%B4%EB%A6%AC%EC%A6%88-%EB%85%B8%ED%8A%B8Release-Note%EB%A5%BC-%EC%9E%91%EC%84%B1%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Thu, 04 May 2023 08:09:47 GMT</pubDate>
            <description><![CDATA[<p><em>릴리즈 노트란 무엇일까? 🤔</em></p>
<p>일상 속에서 릴리즈 노트와 가장 비슷한 노트를 찾을 수 있는 가장 쉬운 방법은 무엇일까요?</p>
<p>제가 생각한 방법은 바로 게임 업데이트(패치) 노트를 확인하는 것입니다.
어떠한 새로운 이벤트들이 추가 됐는지, 캐릭터의 밸런스 패치, 버그 수정 등 쉽게 보면 게임 업데이트 노트에서 가장 쉽게 볼 수 있는 것 같습니다.</p>
<h4 id="릴리즈-노트--게임-패치-노트"><em>릴리즈 노트 === 게임 패치 노트</em></h4>
<p>릴리즈 노트와 게임 패치 노트가 같은 개념인지(?)는 정확하게 모르겠지만..! 
위와 같이 생각하고 접근해봅시다!</p>
<h2 id="릴리즈-노트란-📖">릴리즈 노트란? 📖</h2>
<ul>
<li>소프트웨어 또는 서비스가 출시 또는 업데이트 될 때마다 해당 상품의 배포와 함께 변경 사항, 기능 추가/삭제, 버그 개선 등 변경 사항을 체계적으로 정리하여 정보를 제공하는 문서</li>
<li>릴리즈 노트는 정보 공유 뿐만 아니라 회사에 대한 긍정적인 인상을 심어주는 중요한 역할을 한다.</li>
</ul>
<blockquote>
<p>게임으로 대입해보면 <strong>새로운 캐릭터의 출시, 직업 버그 수정, 기존 사냥터 리뉴얼 등</strong> 여러가지 서비스의 변경 사항을 정리해서 보여줍니다.</p>
<p>이러한 릴리즈 노트를 보면 회사가 서비스를 개선하기 위해 열심히 노력하고 있다고 생각할 수 있습니다.</p>
</blockquote>
<h2 id="릴리즈-노트가-꼭-작성되어야-하는-이유-📚">릴리즈 노트가 꼭 작성되어야 하는 이유 📚</h2>
<ol>
<li>업데이트 정보를 한 곳에 모아 기록함으로써, 내가 작업하지 않은 업데이트 사항도 빠르게 파악 가능</li>
<li>릴리즈 노트를 보면 누구나 제품의 발자취를 한 눈에 파악 가능</li>
<li>우리 회사의 제품 혹은 서비스가 지속적으로 개선되고 최신의 상태를 유지하고 있음을 안내</li>
<li>사용자의 신고와 의견을 반영하고 있다는 인상을 주어 사용자의 적극적인 피드백을 유도</li>
</ol>
<p>구글 클라우드 서비스 팀의 릴리즈 노트를 보면 날짜를 기준으로 정리된 릴리즈 노트를 확인할 수 있습니다.</p>
<blockquote>
<p>릴리즈 노트와 게임 패치 노트를 비교해보면 3, 4번은 오히려 게임 패치 노트에서 더 중요하다고 생각할 정도인데요.</p>
<p>1, 2번은 게임 패치 노트에서 한 눈에 파악하기는 조금 어려운 것 같습니다.</p>
<p>아무래도 패치 노트는 이미지의 추가, 긴 설명 등의 차이가 있기 때문이죠.</p>
</blockquote>
<h2 id="릴리즈-노트의-구성-요소-⚙️">릴리즈 노트의 구성 요소 ⚙️</h2>
<p>릴리즈 노트의 구성요소는 따로 정해져 있지는 않습니다.</p>
<h4 id="회사나-조직마다-준수해야-하는-릴리즈-노트-표준은-존재하지-않는다"><em>회사나 조직마다 준수해야 하는 릴리즈 노트 표준은 존재하지 않는다.</em></h4>
<p>그래서 제가 참고한 구글 클라우드, 카카오 테크, NHN 클라우드 등 여러 서비스의 릴리즈 노트 양식은 다 다릅니다.
하지만 일반적으로 릴리즈 노트는 <strong>버전, 날짜, 구분, 설명</strong>으로 구성됩니다.</p>
<h3 id="버전">버전</h3>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/cc245a9b-e9ef-4db7-a02b-038a1f439c22/image.png" alt=""></p>
<p>버전을 작성하지 않는 서비스들도 있습니다.
하지만 개인적으로 버전을 작성하는 것이 릴리즈 노트를 훨씬 효과적으로 확인할 수 있는 방법이라고 생각합니다.</p>
<blockquote>
<p>독자들은 릴리즈 노트만 보고 신규 업데이트나 버그 픽스 등의 소프트웨어의 변경 범위를 대략적으로 유추할 수 있습니다.</p>
</blockquote>
<h3 id="날짜">날짜</h3>
<p>영어식 표기 또는 국어식 표기 중 하나의 스타일을 정하고 전체 문서에서 일관된 스타일을 유지하는 것이 중요합니다.
구글을 포함한 여러 글로벌 IT 회사들은 스타일 가이드에 날짜 표기 방식에 대한 구체적인 정의를 포함하고 있습니다.</p>
<h3 id="구분">구분</h3>
<p>해당 기능이 신규 추가 항목인지, 또는 수정 항목인지 변경 사항을 빠르게 파악할 수 있도록 도와줍니다.</p>
<p>태그(<code>tag</code>)의 역할을 하고 있습니다. 일반적으로는 <code>New</code>(최초), <code>Feature</code>(기능), <code>Changed</code>(변경), <code>Fixed</code>(수정), <code>Deprecated</code>(중단) 등의 항목이 포함될 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/26fabff9-763a-4cff-9c76-5e46b7b65f33/image.png" alt=""></p>
<blockquote>
<p>해당 구분에 대한 내용도 본인이 속한 조직에서 자유롭게 정할 수 있습니다.</p>
<p>너무 다양하다면 해당 구분 태그를 관리하기 어렵고,너무 적으면 구분 태그로 표현하기가 어려울 것입니다.</p>
</blockquote>
<h3 id="설명">설명</h3>
<p>상품이나 서비스의 특성에 따라 릴리즈 노트의 설명 부분이 한 줄로 간략하게 끝날수도 있고, 자세하게 풀어쓰는 것도 가능합니다.</p>
<p>하지만 일반적으로 릴리즈 노트는 <strong>간략하고 집약적으로 작성하는 것</strong>이 일반적입니다.
그래서 자세하게 내용을 풀어서 쓰고 싶다면 관련 문서 링크를 연결하는 것도 좋습니다.</p>
<h2 id="릴리즈-노트-작성-tip-🙌">릴리즈 노트 작성 Tip 🙌</h2>
<h3 id="버그-수정-및-성능-개선은-지양">&quot;버그 수정 및 성능 개선&quot;은 지양</h3>
<p>위의 문구를 반복적으로 사용하는 것은 지양해야 합니다.</p>
<p>적어도 어떤 버그가 개선되었는지, 어떤 기능이 어떻게 변경되거나 추가 되었는지 사용자가 파악할 수 있도록 작성하는 것이 좋습니다.
릴리즈 노트를 즐겨 읽고 개선된 기능을 빨리 사용해보고 싶어하는 독자들에게 알맞은 정보를 전달해주어야 합니다.</p>
<h3 id="짧게-작성하고-링크를-활용">짧게 작성하고, 링크를 활용</h3>
<p>제가 찾아봤을 때 이 부분은 상반된 의견을 보였는데요.
처음부터 간결하게 쓰려고 노력하면 꼭 들어가야 할 정보가 빠져 있거나, 모호한 노트를 쓰게 된다고 의견을 내는 사람이 있습니다.</p>
<p>반대로 가독성이 떨어지지 않게 최대한 간결하게 적는 것이 중요하다. 너무 길어지만 매뉴얼 본문을 보는 듯한 착각에 빠질 수 있다는 의견을 내는 사람도 있습니다. 그리고 자세한 안내를 원한다면 문서 페이지의 링크를 안내하는 것이 좋다고 말합니다.</p>
<blockquote>
<p>사실 두 의견의 결과는 모두 짧게 작성하는 것입니다.
하지만 과정의 차이가 있을 뿐이죠. 본인이 훈련하고 싶은 방법으로 작성해보는 것이 어떨까요? </p>
</blockquote>
<h3 id="일관된-용어를-사용하라">일관된 용어를 사용하라</h3>
<p>릴리즈 노트를 작성하는 작성자마자 사용하는 용어가 다른 경우가 존재합니다.</p>
<p><code>BOT Response 기능 추가</code>, <code>Bot 응답 개선</code>,  <code>봇의 응답 방식 개선</code> 등 같은 의미를 가지고 있지만 작성자가 사용하는 용어마다 전혀 다른식으로 표현이 됩니다.</p>
<p>이러한 경우 동일한 의미를 가진 여러 단어를 일관된 용어를 사용할 필요가 있습니다. </p>
<blockquote>
<p>매우 사소해 보이지만, 매우 중요한 포인트라고 생각이 듭니다.
조직 내에서 작성자의 역할이 분명하거나, 모든 개발자가 작성에 참여할 경우에는 원활한 소통이 필요할 것입니다.</p>
</blockquote>
<h2 id="사용자-관점에서-쉽게-작성하라">사용자 관점에서 쉽게 작성하라</h2>
<p>릴리즈 노트는 독자를 위한 문서입니다.
그렇기 때문에 사용자가 주어라고 생각하고 글을 작성하는 것이 가독성을 높일 수 있습니다.</p>
<h3 id="시각적-효과그룹화를-적용하라">시각적 효과(그룹화)를 적용하라</h3>
<p>사용자는 자신이 제보한 버그가 수정되었는지, 이번 버전에는 신규 기능이 있는지 등의 특정 목적을 가지고 릴리즈 노트를 읽습니다.
같은 내용이라도 색을 활용하여 구분을 나타내고 여백 또는 구분선 등을 활용하여 섹션을 구분하는 등 시각적 효과를 적용하면 릴리즈 노트의 가독성을 개선할 수 있습니다.</p>
<h2 id="릴리즈-노트-작성하기">릴리즈 노트 작성하기</h2>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/9d44ab1a-e4f6-49ba-88e3-6c3d9a575dbc/image.png" alt=""></p>
<p>제가 사내 릴리즈 노트를 작성하면서 많이 참고했던 kakaoi의 릴리즈 노트입니다.
<code>Bot 시작 가이드</code>라는 서비스에 대한 릴리즈 노트를 가져 왔는데요.
해당 릴리즈 노트의 버전을 쭉 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/bbf22e01-79d5-4136-b01e-2fffee7f1c8b/image.png" alt=""></p>
<p>혹은 날짜를 기준으로 하위에 서비스명을 두고 릴리즈 노트를 작성해도 됩니다.
해당 릴리즈 노트는 google cloude service 릴리즈 노트입니다.
버전을 따로 존재하지 않고, 날짜를 기준으로 릴리즈 노트를 작성하고 있습니다.</p>
<p>두 릴리즈 노트 모두 설명은 길지 않게, 추가적인 설명은 텍스트에 링크를 붙여놓은 것을 볼 수 있습니다.</p>
<h2 id="마무리">마무리</h2>
<p>사내에서 사용할 릴리즈 노트를 작성하기 위해서 처음 릴리즈 노트를 찾아보고 정리해봤는데요.
릴리즈 노트의 경우에는 기존의 IT 기업들의 사례를 잘 조합해서 사용하는 것이 좋다고 생각합니다.
그래서 아예 처음부터 새로운 양식으로 만들어봐야겠다는 생각은 하지 않았던 것 같습니다.</p>
<blockquote>
<p>출처에 첨부된 카카오 테크의 릴리즈 노트 작성법을 보시면 제가 정리한 내용보다 더 자세한 내용을 확인하실 수 있습니다.</p>
</blockquote>
<h2 id="출처">출처</h2>
<ul>
<li><p><a href="https://tech.kakaoenterprise.com/113">https://tech.kakaoenterprise.com/113</a></p>
</li>
<li><p><a href="https://engineering.linecorp.com/ko/blog/write-the-docs-prague-2018-recap/">https://engineering.linecorp.com/ko/blog/write-the-docs-prague-2018-recap/</a></p>
</li>
<li><p><a href="https://cloud.google.com/release-notes">https://cloud.google.com/release-notes</a></p>
</li>
<li><p><a href="https://docs.kakaoi.ai/kakao_work/release_note/">https://docs.kakaoi.ai/kakao_work/release_note/</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 코딩 컨벤션]]></title>
            <link>https://velog.io/@s_sangs/TypeScript-%EC%BD%94%EB%94%A9-%EC%BB%A8%EB%B2%A4%EC%85%98</link>
            <guid>https://velog.io/@s_sangs/TypeScript-%EC%BD%94%EB%94%A9-%EC%BB%A8%EB%B2%A4%EC%85%98</guid>
            <pubDate>Thu, 04 May 2023 00:06:47 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트 및 타입스크립트에 대한 코딩 컨벤션을 주도적으로 다루게 될 기회가 생겨서 자료를 정리해보았습니다.</p>
<p>다른 자료들을 찾아보시면 훨씬 더 많은 컨벤션 내용을 확인하실 수 있습니다.
저는 TypeScript 컨벤션으로 분류될 수 있을만한 내용만 간단하게 추려보았습니다.
대부분의 내용은 JavaScript 코딩 컨벤션과 관련된 내용이 많았습니다. 📚</p>
<h2 id="인터페이스-interface">인터페이스 (<code>Interface</code>)</h2>
<p><code>PascalCase</code>를 사용합니다.
<code>I</code>를 접두어로 사용하지 않습니다.</p>
<ul>
<li>이전에는 인터페이스 변수 앞에 <code>I</code>를 붙이는 경우가 많았는데 현재는 비관습적인 이유로 사용하지 않습니다.</li>
</ul>
<pre><code class="language-typescript">// Bad
interface IFoo {
}

// Good
interface Foo {
}</code></pre>
<h2 id="타입-type">타입 (<code>Type</code>)</h2>
<p><code>PascalCase</code>를 사용합니다.
멤버는 <code>camelCase</code>를 사용합니다.</p>
<pre><code class="language-typescript">// Bad
type car {
    ModelInfo: string;
}

// Good
type Car {
    modelInfo: string;
}</code></pre>
<h2 id="type-vs-interface"><code>Type</code> vs <code>Interface</code></h2>
<p><strong><code>Union</code>이나 <code>Intersection</code>이 필요할 때 Type을 사용합니다.</strong></p>
<pre><code class="language-typescript">type Foo = number | { someProperty: number }</code></pre>
<p><strong><code>extends</code> 또는 <code>implements</code>를 사용하고 싶을 때는 <code>Interface</code>를 사용합니다.</strong></p>
<pre><code class="language-typescript">interface Foo {
    foo: string;
}

interface FooBar extends Foo {
  bar: string;
}

class X implements FooBar {
    foo: string;
    bar: string;
}</code></pre>
<h2 id="네임스페이스-namespace">네임스페이스 (<code>namespace</code>)</h2>
<p><code>PascalCase</code>를 사용합니다.</p>
<ul>
<li>타입스크립트 팀에서 정한 약속입니다.</li>
<li>네임스페이스들은 정적멤버를 갖는 클래스, 클래스 이름도 <code>PascalCase</code>를 사용하기 때문에 동일하게 사용합니다.<pre><code class="language-typescript">// Bad
namespace foo {
}
</code></pre>
</li>
</ul>
<p>// Good
namespace Foo {
}</p>
<pre><code>


## `enum`

`PascalCase`를 사용합니다.
`enum`의 멤버에는 `PascalCase`를 사용합니다.
- 타입스크립트 팀에서 정한 약속입니다.
```typescript
// Bad
enum color {
    red
}

// Good
enum Color {
    Red
}</code></pre><h2 id="any-vs-unknown"><code>any</code> vs <code>unknown</code></h2>
<ul>
<li><code>unknown</code> 타입을 사용합니다.</li>
<li><code>any</code>, <code>unknown</code> 타입 모두 아무때나 사용할 수 있지만 <code>unknown</code> 타입은 사용하는 쪽에서 방어처리를 해서 안전하게 사용이 가능합니다.</li>
<li><code>any</code> 타입은 타입스크립트를 쓰는 의미가 없게 되버릴 수 있습니다.</li>
</ul>
<pre><code class="language-typescript">function prettyPrint(x: unknown): string {
  if (Array.isArray(x)) {
    return &quot;[&quot; + x.map(prettyPrint).join(&quot;, &quot;) + &quot;]&quot;
  }
  if (typeof x === &quot;string&quot;) {
    return `&quot;${x}&quot;`
  }
  if (typeof x === &quot;number&quot;) {
    return String(x)
  } 
  return &quot;etc.&quot;
}</code></pre>
<p><code>x</code>를 <code>any</code>로 했을 경우 <code>map()</code>, <code>join()</code>을 사용할 수 있는데 <code>unknown</code>일 때 <code>x</code>가 배열인 경우에만 <code>map()</code>, <code>join()</code>을 사용할 수 있도록 강제해줍니다.</p>
<h2 id="null-vs-undefined"><code>null</code> vs <code>undefined</code></h2>
<ul>
<li>명백히 값이 없을 때에도 사용하지 않도록 합니다.</li>
<li>타입스크립트에서 <code>type</code>으로 구조를 암시할 수 있도록 합니다.<pre><code class="language-typescript">// Bad
let foo = { x: 123, y: undefined }
</code></pre>
</li>
</ul>
<p>// Good
let foo = { x: number, y?: number } = { x: 123 }</p>
<pre><code>


일반적으로 `undefined`를 사용합니다.

```typescript
return undefined</code></pre><p><code>null</code>이나 <code>undefined</code> 값을 갖는 객체는 <code>truthy</code>하게 검사합니다.</p>
<pre><code class="language-typescript">// Bad
if (error === null)

// Good
if (error)</code></pre>
<p><code>null</code>이나 <code>undefined</code>를 체크할 때 <code>===</code> 혹은 <code>!==</code>를 사용하지 않고 <code>==</code> 혹은 <code>!=</code>를 사용합니다.</p>
<ul>
<li><code>null</code>이나 <code>undefined</code>에는 작동하지만 다른 <code>fasly</code> 값들 (&#39;&#39;, 0, <code>false</code>)에는 작동하지 않습니다.<pre><code class="language-typescript">// Bad
if (error !== null)
</code></pre>
</li>
</ul>
<p>// Good
if (error != null)</p>
<p>```</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://radlohead.gitbook.io/typescript-deep-dive/styleguide">https://radlohead.gitbook.io/typescript-deep-dive/styleguide</a></li>
<li><a href="https://techblog.woowahan.com/9804/">https://techblog.woowahan.com/9804/</a></li>
<li><a href="https://738.github.io/clean-code-typescript/">https://738.github.io/clean-code-typescript/</a></li>
<li><a href="https://github.com/tipjs/javascript-style-guide">https://github.com/tipjs/javascript-style-guide</a></li>
<li><a href="https://velog.io/@cada/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BD%94%EB%94%A9-%EB%B0%8F-%EB%84%A4%EC%9D%B4%EB%B0%8D-%EC%BB%A8%EB%B2%A4%EC%85%98-1%ED%8E%B8">https://velog.io/@cada/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BD%94%EB%94%A9-%EB%B0%8F-%EB%84%A4%EC%9D%B4%EB%B0%8D-%EC%BB%A8%EB%B2%A4%EC%85%98-1%ED%8E%B8</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS-in-JS에서 Stylelint 사용하기 (feat. emotion, styled-components)]]></title>
            <link>https://velog.io/@s_sangs/CSS-in-JS-Stylelint-feat.-emotion-styled-components</link>
            <guid>https://velog.io/@s_sangs/CSS-in-JS-Stylelint-feat.-emotion-styled-components</guid>
            <pubDate>Wed, 03 May 2023 16:24:34 GMT</pubDate>
            <description><![CDATA[<p>기존에 <code>CSS-in-JS</code>로 <code>emotion</code>을 사용하고 있었는데요.</p>
<p><code>styled-components</code>와 달리 <code>emotion</code>에서는 <code>stylelint</code>를 설정하는 방법이 따로 없었습니다.
공식문서를 봐도 <code>stylelint</code>와 관련된 내용을 찾아보기 어려웠습니다. 🤦‍♂️</p>
<p>몇 일동안 정말 다양한 문서를 봤던 것 같습니다...
모든 포스팅이 그렇듯 시간이 지남에 따라 버전에 대한 문제도 있었고, 더 이상 지원하지 않는 플러그인을 가지고 적용하는 방법 등 제대로 적용할 수 있는 방법을 찾지 못했습니다.</p>
<p>그래서 <code>styled-components</code>로 옮겨가야 되겠다라고 생각하고 있었죠.. 🚚</p>
<p>저는 <code>emotion</code>에서도 주로 <code>styled</code> 키워드를 자주 사용하는데요.
그래서 <code>styled-components</code>의 <code>stylelint</code> 설정 방식을 <code>emotion</code>에 그대로 적용해보았습니다!
다행히..! <code>emotion</code>의 <code>styled</code> 키워드에서는 잘 작동을 했습니다!! 🙌</p>
<p>저와 같이 <code>emotion</code>과 <code>stylelint</code>, css 속성 정렬을 같이 해보고 싶으신 분들은 아래의 포스팅을 봐주시면 됩니다!</p>
<h2 id="emotion-설치">Emotion 설치</h2>
<h3 id="react">React</h3>
<pre><code class="language-shell">$ yarn add @emotion/react @emotion/styled</code></pre>
<h3 id="react-native">React Native</h3>
<pre><code class="language-bash">$ yarn add @emotion/react @emotion/native</code></pre>
<h2 id="stylelint-설치">StyleLint 설치</h2>
<pre><code class="language-shell">$ yarn add --dev stylelint stylelint-config-standard stylelint-order postcss-styled-syntax</code></pre>
<ul>
<li><code>stylelint</code> : <code>stylelint</code>를 사용하기 위한 기본적인 패키지</li>
<li><code>stylelint-config-standard</code> : <code>stylelint</code>에서 표준으로 제공하는 규칙에 대한 패키지</li>
<li><code>stylelint-order</code> : <code>CSS</code> 속성에 대한 그룹 및 순서를 작성할 수 있는 패키지</li>
<li><code>postcss-styled-syntax</code> : <code>styled</code>로 작성된 <code>CSS</code> 속성들을 파싱해주는 패키지</li>
</ul>
<p><strong><em><code>stylelint</code> 15버전 이상을 기준으로 작성했습니다.</em></strong></p>
<p><code>styled-components</code>의 <code>stylelint</code> 설정 방식을 그대로 가져와서 <code>emotion</code>에 적용했습니다.
그래서 <code>emotion</code>에서 사용하는 <code>The css Props</code>와 같은 형식에는 적용이 되지 않을수도 있습니다.</p>
<h2 id="stylelintrcjson-파일-작성"><code>.stylelintrc.json</code> 파일 작성</h2>
<pre><code class="language-json">{  
  &quot;extends&quot;: [&quot;stylelint-config-standard&quot;],  
  &quot;plugins&quot;: [&quot;stylelint-order&quot;],  
  &quot;customSyntax&quot;: &quot;postcss-styled-syntax&quot;,  
  &quot;rules&quot;: {  
      // css 속성 작성 시 empty line 관련 설정
    &quot;declaration-empty-line-before&quot;: [  
      &quot;always&quot;,  
      {  
        &quot;ignore&quot;: [  
          &quot;first-nested&quot;,  
          &quot;after-comment&quot;,  
          &quot;after-declaration&quot;,  
          &quot;inside-single-line-block&quot;  
        ]  
      }  
    ],  
    &quot;order/order&quot;: [&quot;custom-properties&quot;, &quot;declarations&quot;],  

    // css 속성 그룹 및 순서 설정
    &quot;order/properties-order&quot;: [  
      {  
          // 그룹 이름 설정
        &quot;groupName&quot;: &quot;Layout&quot;,  
        // 그룹 내부 emptyline 사용 여부
        &quot;noEmptyLineBetween&quot;: true,  
        // 그룹 css 속성 멤버
        &quot;properties&quot;: [  
          &quot;display&quot;,  
          &quot;visibility&quot;,  
          &quot;overflow&quot;,  
          &quot;float&quot;,  
          &quot;clear&quot;,  
          &quot;position&quot;,  
          &quot;top&quot;,  
          &quot;right&quot;,  
          &quot;bottom&quot;,  
          &quot;left&quot;,  
          &quot;z-index&quot;  
        ]  
      },  
      {  
        &quot;groupName&quot;: &quot;Box&quot;,  
        &quot;emptyLineBefore&quot;: &quot;always&quot;,  
        &quot;noEmptyLineBetween&quot;: true,  
        &quot;properties&quot;: [  
          &quot;width&quot;,  
          &quot;height&quot;,  
          &quot;margin&quot;,  
          &quot;margin-top&quot;,  
          &quot;margin-right&quot;,  
          &quot;margin-bottom&quot;,  
          &quot;margin-left&quot;,  
          &quot;padding&quot;,  
          &quot;padding-top&quot;,  
          &quot;padding-right&quot;,  
          &quot;padding-bottom&quot;,  
          &quot;padding-left&quot;,  
          &quot;border&quot;  
        ]  
      },  
      {  
        &quot;groupName&quot;: &quot;Background&quot;,  
        &quot;emptyLineBefore&quot;: &quot;always&quot;,  
        &quot;noEmptyLineBetween&quot;: true,  
        &quot;properties&quot;: [&quot;background-color&quot;]  
      },  
      {  
        &quot;groupName&quot;: &quot;Font&quot;,  
        &quot;emptyLineBefore&quot;: &quot;always&quot;,  
        &quot;noEmptyLineBetween&quot;: true,  
        &quot;properties&quot;: [  
          &quot;color&quot;,  
          &quot;font-style&quot;,  
          &quot;font-weight&quot;,  
          &quot;font-size&quot;,  
          &quot;line-height&quot;,  
          &quot;letter-spacing&quot;,  
          &quot;text-align&quot;,  
          &quot;text-indent&quot;,  
          &quot;vertical-align&quot;,  
          &quot;white-space&quot;  
        ]  
      },  
      {  
        &quot;groupName&quot;: &quot;Animation&quot;,  
        &quot;emptyLineBefore&quot;: &quot;always&quot;,  
        &quot;noEmptyLineBetween&quot;: true,  
        &quot;properties&quot;: [&quot;animation&quot;]  
      }  
    ]  
  }  
}</code></pre>
<blockquote>
<p><code>stylelint-order</code> 플러그인에 대한 내용을 <code>github</code>을 통해서 추가적으로 찾아보시는 것을 추천드립니다.</p>
<p>페이지에 룰에 대한 자세한 설명들이 포함되어 있습니다.</p>
</blockquote>
<h2 id="stylelint-script-작성">StyleLint script 작성</h2>
<pre><code class="language-json">// package.json
{
    &quot;scripts&quot;: {
        &quot;lint:styled&quot;: &quot;stylelint &#39;./src/**/*.styles.ts&#39; --fix&quot;,
    }
}
</code></pre>
<h2 id="lint-검사">Lint 검사</h2>
<pre><code class="language-shell">npm run lint:styled</code></pre>
<blockquote>
<p>앞으로 Lint 검사를 <code>Husky</code>와 같이 <code>git hook</code>과 연계해서 사용하거나
<code>vscode</code>의 경우에는 <code>stylelint</code> 플러그인을 잘 지원해주는 것으로 알고 있습니다.
<code>Intelij</code>의 경우에는 <code>File Watcher</code> 플러그인을 별도로 설치해서 사용해야 합니다.</p>
</blockquote>
<h2 id="적용-예시">적용 예시</h2>
<pre><code class="language-typescript">// components/CustomText/CustomText.styles.ts
import styled from &#39;@emotion/native&#39;;  

export const CustomText = styled.Text`  
  display: flex;
  width: 200px;
  margin: 10px;
  padding: 10px;
  border-radius: 100%;

  background-color: black;  

  color: #e9ecef;
  font-weight: bold;
  font-size: 14px;  

  animation: ease;`;</code></pre>
<p>현재 느낀 단점은 <code>.stylelintrc.json</code> 파일 내부에 작성하지 않은  <code>css</code>의 속성의 경우에는 어떠한 룰도 적용되지 않는 점입니다.</p>
<p>플러그인에서 어느정도 그룹핑을 제공하면 좋을 것 같습니다.</p>
<blockquote>
<p><code>stylelint-semantic-groups</code>, <code>stylelint-config-rational-order</code>, <code>stylelint-config-idiomatic-order</code> 등의 플러그인을 사용하면 기본적으로 제공하는 그룹핑이 있는 것 같습니다.</p>
</blockquote>
<h2 id="정리">정리</h2>
<p><code>emotion</code> + <code>stylelint</code>를 적용하기 위해서 정말 많은 자료를 찾아보고 시간을 사용했던 것 같습니다.. 🤯</p>
<p>아직 <code>stylelint-config-standard</code>에 대한 자세한 룰을 적용하지 않았고, 정렬에 대한 자세한 룰도 적용하지 않았습니다.
본인이 사용하시고 싶은 <code>CSS 컨벤션</code>이 있다면, 이번 기회를 통해서 시스템화 하는 것도 좋은 기회라고 생각합니다!</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://emotion.sh/docs/@emotion/native">https://emotion.sh/docs/@emotion/native</a></li>
<li><a href="https://styled-components.com/docs/tooling#stylelint">https://styled-components.com/docs/tooling#stylelint</a></li>
<li><a href="https://github.com/hudochenkov/stylelint-order">https://github.com/hudochenkov/stylelint-order</a></li>
<li><a href="https://github.com/theKashey/stylelint-semantic-groups">https://github.com/theKashey/stylelint-semantic-groups</a></li>
<li><a href="https://github.com/constverum/stylelint-config-rational-order">https://github.com/constverum/stylelint-config-rational-order</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 커밋 메시지 작성법]]></title>
            <link>https://velog.io/@s_sangs/Git-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%9E%91%EC%84%B1%EB%B2%95</link>
            <guid>https://velog.io/@s_sangs/Git-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%9E%91%EC%84%B1%EB%B2%95</guid>
            <pubDate>Mon, 01 May 2023 15:01:33 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>업무, 개인 프로젝트 등 우리는 커밋 메시지를 매일 작성합니다.</p>
<p>개인적으로 그만큼 제대로 신경쓰지 않고, 커밋 메시지를 작성했던 것 같습니다.
오늘은 이렇게 신경쓰지 않은 커밋 메시지 작성법에 대해서 나눠보려고 합니다.
사실 회사에서는 <em>이렇게 커밋 메시지를 작성하세요!</em> 라고 하는 내용은 없습니다.</p>
<p>기본적으로 많이 사용하는 <code>[FEAT]</code>, <code>[FIX]</code>,  <code>[REMOVE]</code>와 같은 타입과 제목 정도는 작성하고 있었습니다.</p>
<p>하지만 점점 작성하다보니, <em>내가 커밋 메시지를 잘 쓰고 있는건가?</em> 🤔 라는 의문이 들기 시작했습니다.
과거의 커밋 이력을 보고 있는데, 제가 작성한 커밋 메시지를 이해 못하고 있었습니다... 🤯
이 순간은 매우매우 충격적이었습니다..</p>
<p>사실 평소에도 <em>나는 커밋 메시지를 자세하게 잘 쓰고 있어!</em> 라는 생각을 하지는 않았습니다.
하지만 실제로 커밋 메시지를 보니 왜 이런 기능을 작성했는지, 자세한 내용은 하나도 이해가 되지 않았습니다..
대충 어떤 내용의 작업이라는 것만 적혀있고, 왜 이러한 코드를 썼는지, 자세한 내용들이 안 남아 있었습니다.</p>
<p>부족함을 알았으니, 미래의 나를 조금이라도 덜 힘들게 하기 위해서, 커밋 메시지 작성법에 대해서 정리를 해보려고 합니다.</p>
<h2 id="구조">구조</h2>
<p>제목, 본문, 꼬리말, 세가지 파트로 구분합니다.</p>
<p>각 파트는 빈 줄을 두고 구분합니다.</p>
<p>다른 포스팅을 많이 참고하려고 했는데, 대부분 동일한 컨벤션을 가지고 있었습니다.</p>
<pre><code>type: 제목

본문

꼬리말</code></pre><h2 id="제목">제목</h2>
<h3 id="type-제목"><code>type: 제목</code></h3>
<h3 id="type"><code>type:</code></h3>
<ul>
<li><code>feat</code> : 새로운 기능 추가</li>
<li><code>fix</code> : 버그 수정</li>
<li><code>docs</code> : 문서 업데이트</li>
<li><code>style</code> : <code>style</code>과 관련 코드 수정</li>
<li><code>refactor</code> : 코드 리팩토링</li>
<li><code>test</code> : 테스트 코드 작성, 수정</li>
<li><code>chore</code> : 패키지 설치 및 환경 설정</li>
<li><code>rename</code> : 파일 혹은 폴더명 수정 혹은 이동 </li>
<li><code>remove</code> : 파일 삭제</li>
</ul>
<h3 id="제목-1"><code>제목</code></h3>
<ul>
<li>간략하게 변경 이유와 이 커밋으로 어떤 점이 달라지는지 명시합니다.</li>
<li>과거형 대신 현재형으로 작성합니다.</li>
<li>끝에 점(.)을 붙이지 않습니다.</li>
</ul>
<pre><code>feat: 네이버 소셜 로그인 기능을 구현 함. (X)

feat: 네이버 소셜 로그인 기능 구현 (O)</code></pre><p>다른 포스팅을 많이 참고하려고 했는데, 대부분 비슷한 컨벤션을 가져가고 있었습니다.
그리고 <code>type:</code>을 7가지로 작성하신 분들이 많았습니다.</p>
<p>개인적으로 굳이 7개로 한정해서 나눌 필요는 없다고 생각이 듭니다.
<code>type</code>은 자유롭게 넣고 빼고 해도 괜찮다고 생각합니다.
<em>(사실 <code>feat</code>, <code>fix</code>를 제일 많이 사용하겠지요..!)</em></p>
<p>대문자로 시작하지 않는다는 규칙도 있었는데요.
이 부분은 영어로 커밋 메시지를 작성할 때 대문자로 시작하지 말라는 이야기였습니다.
개인적으로 아직은 영어로 커밋 메시지를 작성할 용기가 나지 않기 때문에.. 패스하도록 하겠습니다 🏃</p>
<h2 id="본문">본문</h2>
<ul>
<li>긴 설명이 필요한 경우에 작성합니다.</li>
<li>어떻게 보다는 <strong>무엇을</strong>, <strong>왜</strong> 변경했는지에 대해서 작성합니다.</li>
<li>본문의 양에 구애 받지 않고, 최대한 상세하게 작성합니다.</li>
<li>이 변경을 통해서 <code>side effect</code>나 고려해야 될 사항이 있다면 작성합니다.</li>
</ul>
<p>예시를 한 번 작성해보려고 했는데요.</p>
<p><strong>무엇을, 왜</strong> 변경했는지에 대한 내용을 작성하는게 꽤나 힘든 것 같습니다. 🤔</p>
<h2 id="꼬리말">꼬리말</h2>
<ul>
<li>꼬리말은 <code>optional</code>입니다.</li>
<li><code>유형: #이슈 ID</code> 형식으로 작성합니다.</li>
</ul>
<pre><code>Fixes: #45
Related to: #34, #23</code></pre><h2 id="마무리">마무리</h2>
<p>대부분의 개발자들은 커밋의 순서를 따라가면서 다른 동료분들이 작성한 코드를 파악합니다.
그리고 코드에 대한 의견이 있다면, 리뷰를 남기면서 코드리뷰를 진행하기도 합니다.</p>
<p>저 또한 코드리뷰를 진행할 때 그런식으로 진행하는데요.
이 때 커밋 메시지를 잘 작성해두면 코드 리뷰 혹은 저처럼 과거의 내용을 파악할 때 조금 더 효과적으로 내용을 확인할 수 있을거라고 기대합니다.</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://devinn.dev/blog/detail.html?id=115">https://devinn.dev/blog/detail.html?id=115</a></li>
<li><a href="https://velog.io/@shin6403/Git-git-%EC%BB%A4%EB%B0%8B-%EC%BB%A8%EB%B2%A4%EC%85%98-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0">https://velog.io/@shin6403/Git-git-%EC%BB%A4%EB%B0%8B-%EC%BB%A8%EB%B2%A4%EC%85%98-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</a></li>
<li><a href="https://overcome-the-limits.tistory.com/entry/%ED%98%91%EC%97%85-%ED%98%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-git-%EC%BB%A4%EB%B0%8B%EC%BB%A8%EB%B2%A4%EC%85%98-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0">https://overcome-the-limits.tistory.com/entry/%ED%98%91%EC%97%85-%ED%98%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-git-%EC%BB%A4%EB%B0%8B%EC%BB%A8%EB%B2%A4%EC%85%98-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git & Github 톺아보기 (w. 명령어 정리)]]></title>
            <link>https://velog.io/@s_sangs/Git-Github-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0-w.-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@s_sangs/Git-Github-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0-w.-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 29 Apr 2023 16:34:35 GMT</pubDate>
            <description><![CDATA[<p>오늘은 git 명령어에 대해서 톺아보는 시간을 가져보려고 합니다.
최근에 <strong><em>톺아보기</em></strong> 라는 단어가 제 눈에 많이 보였는데요
톺아보기는 <strong><em>구석구석 꼼꼼히 살펴보기</em></strong> 라는 뜻이 됩니다!</p>
<p>본 뜻을 찾아보면, &#39;톺다&#39;라는 뜻은 <em>틈이 있는 곳마다 모조리 더듬어 뒤지면서 찾다</em> 라는 뜻입니다.
&#39;톺아보기&#39;는 <em>샅샅이 톺아 나가면서 살피다</em> 라는 뜻을 가지고 있습니다.</p>
<h2 id="git이란-무엇인가-🤔">Git이란 무엇인가? 🤔</h2>
<ul>
<li>리누스 토발즈가 리눅스 커널 개발에 사용할 관리 도구 용도로 개발</li>
<li><strong>분산 버전 관리 시스템</strong>으로 지역 저장소와 원격 저장소가 존재</li>
<li>여러 사람이 같은 코드를 수정하고 공유하며, 하나의 파일로 모든 버전을 관리할 수 있다. 또한 동시에 같은 부분을 수정했을 때 생기는 문제들을 해결할 수 있다.</li>
</ul>
<br />

<p><code>git</code>을 사용하는 가장 큰 이유는 버전관리와 협업입니다.</p>
<p>꼭 <code>git</code>을 써야만 버전관리를 할 수 있는 것은 아닙니다. 하지만 많은 개발자들이 보편적으로 <code>git</code>을 사용하고 있고, 다른 개발자와 협업을 하기 위해서는 많이 사용하는 것을 먼저 배우는 것이 좋겠죠?</p>
<p><code>git</code>은 지역 저장소에서 버전 관리가 수행됩니다. 그렇기 때문에 원격 저장소나 네트워크에 문제가 있어도 작업이 가능합니다.
원격 저장소는 여러 사람들이 협업을 위해 버전이 공동으로 관리되는 곳입니다.
자신의 버전 내역을 반영하거나, 다른 개발자의 반영된 버전 내역을 가져올 때 사용합니다.</p>
<p>그렇다면 <code>github</code>는 무엇일까요?</p>
<h2 id="github는-무엇인가-🤔">Github는 무엇인가? 🤔</h2>
<ul>
<li><code>git</code> 저장소 호스팅을 지원하는 웹 서비스</li>
</ul>
<p><code>git</code>을 사용하는 프로젝트를 지원하는 웹 호스팅 서비스이기 때문에, <code>git</code>을 사용하는 프로젝트를 모두 <code>github</code>에서 관리할 수 있습니다.
<code>gitlab</code>처럼 다른 호스팅 서비스를 이용할 수도 있습니다.</p>
<h2 id="git-사용법-🔨">Git 사용법 🔨</h2>
<p><code>git</code>의 여러 명령어를 통해서 <code>git</code>의 사용법을 알아보려고 합니다!</p>
<h3 id="git-init"><code>git init</code></h3>
<p>처음 <code>git</code>을 사용할 때 필요한 명령어입니다. 최초 한 번만 입력하면 됩니다.</p>
<blockquote>
<p><code>git</code> 명령어 위주의 설명이기 때문에 <code>github</code> 저장소를 생성하는 작업은 스킵했습니다.</p>
</blockquote>
<h3 id="계정-정보-입력">계정 정보 입력</h3>
<pre><code class="language-bash">git config --global user.email &lt;myEmail&gt;
git config --global user.name &lt;myName&gt;</code></pre>
<h4 id="수정">수정</h4>
<pre><code class="language-bash">git config --global --edit</code></pre>
<h3 id="git-status"><code>git status</code></h3>
<ul>
<li><code>git</code>으로 관리되고 있는 파일의 상태를 확인할 수 있다.</li>
</ul>
<h3 id="git의-3가지-상태"><code>git</code>의 3가지 상태</h3>
<h4 id="modified"><code>modified</code></h4>
<ul>
<li>파일을 수정하면 그 파일은 <code>modified</code> 상태가 된다.</li>
</ul>
<h4 id="staged"><code>staged</code></h4>
<ul>
<li>변경된 파일을 <code>git add</code> 명령어를 통해서 <code>stage area</code>로 올리면 <code>staged</code> 상태가 된다.</li>
</ul>
<h4 id="committed"><code>committed</code></h4>
<ul>
<li><code>staged</code> 파일을 <code>git commit -m &lt;message&gt;</code>를 통해서 해당 파일을 <code>committed</code> 상태로 바꿀 수 있다.</li>
<li>여기까지 진행하고 <code>git push</code>가 일어나야 원격 저장소에 해당 내용이 반영된다.</li>
</ul>
<h4 id="untracked-files"><code>untracked files</code></h4>
<ul>
<li>아직 <code>git</code>이 관리하지 않는 파일</li>
<li>보안에 위협이 되는 파일은 <code>git</code>으로 관리하지 않는 것을 권장
<img src="https://velog.velcdn.com/images/s_sangs/post/d98f2845-fa35-4a6f-a53b-3563b56838bc/image.png" alt=""></li>
</ul>
<p><code>git init</code> 명령어를 실행하고 새로운 파일을 추가하게 되면 <code>untracked file</code>이 추가됩니다.</p>
<p><code>git status</code> 명령어를 통해 확인할 수 있습니다.</p>
<h3 id="git-add-filename"><code>git add &lt;fileName&gt;</code></h3>
<ul>
<li><code>modified</code> 상태의 파일을  <code>staged</code> 상태로 변경</li>
<li>해당 파일을 <code>stage</code>에 올림 (<code>staged</code> 상태)</li>
<li><code>git add .</code> 명령어를 통해서 <code>stage</code>에 올라가지 않은 파일 모두를 <code>stage</code>에 올릴 수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/16a6ffe2-116f-4b89-b229-cd329752433d/image.png" alt=""></p>
<p>새로 만든 파일을 해당 명령어로 입력하게 된 경우 위와 같은 화면을 볼 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/9e7420bc-2cc2-447d-98af-33403c18d3af/image.png" alt=""></p>
<p>이미 <code>git</code>에서 관리하고 있는 파일이 수정된 경우에는 <code>modified</code>라고 파일명 앞에 나타납니다.</p>
<h3 id="git-restore-filename"><code>git restore &lt;fileName&gt;</code></h3>
<ul>
<li><code>modified</code> 상태의 파일을 수정 이전의 상태로 변경</li>
<li>모든 파일을 초기화하려면 <code>git restore .</code> 명령어 사용</li>
</ul>
<h3 id="git-restore---staged-filename"><code>git restore --staged &lt;fileName&gt;</code></h3>
<pre><code class="language-bash">git restore --staged &lt;fileName&gt;</code></pre>
<ul>
<li><code>staged</code> 상태의 파일을 <code>modified</code> 상태로 변경</li>
<li><code>stage</code>에 올라간 <code>fileName</code>을 <code>modified</code> 상태로 변경</li>
<li>새로 추가된 파일의 경우에는 <code>untracked files</code>로 변경 됨</li>
<li>모든 파일을 초기화하려면 <code>git restore --staged .</code> 명령어 사용</li>
</ul>
<h3 id="git-rm"><code>git rm</code></h3>
<pre><code class="language-bash">git rm &lt;fileName&gt;</code></pre>
<ul>
<li>원격저장소와 로컬 저장소 파일을 모두 삭제</li>
</ul>
<pre><code class="language-bash">git rm --cached &lt;fileName&gt;</code></pre>
<ul>
<li>로컬 저장소의 파일은 보존하고, 원격 저장소에 있는 파일만 삭제</li>
</ul>
<h3 id="gitignore"><code>.gitignore</code></h3>
<ul>
<li>해당 파일에 작성된 파일, 폴더는 <code>git</code>에서 관리하지 않음</li>
<li>매번 <code>git rm</code> 관련 명령어를 쓰지 않아도 된다.</li>
</ul>
<h3 id="git-commit"><code>git commit</code></h3>
<pre><code class="language-bash">git commit</code></pre>
<ul>
<li>해당 명령어만 입력하면 <code>vim</code>을 통해서 커밋 메시지 작성 가능</li>
</ul>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/33c1b817-67a5-41a1-88cb-3c20a754862d/image.png" alt=""></p>
<pre><code class="language-bash">git commit -m &quot;Commit Message&quot;</code></pre>
<ul>
<li>보편적으로 사용하는 <code>git commit</code> 명령어<br />


</li>
</ul>
<pre><code class="language-bash">git commit &lt;file&gt; &lt;file2&gt; &lt;file3&gt; -m &quot;Commit Message&quot;</code></pre>
<ul>
<li>여러 파일을 선택적으로 커밋하고 싶을 때 사용</li>
</ul>
<br />


<pre><code class="language-bash">git commit -am &quot;Commit Message&quot;</code></pre>
<ul>
<li><code>git add</code>와 <code>git commit</code> 명령어를 한 번에 사용 가능</li>
<li>반복 작업을 줄여줄 수 있다.</li>
</ul>
<blockquote>
<p>커밋 메시지를 길게 입력하고 싶다면</p>
<pre><code class="language-bash">git commit -a</code></pre>
<p>명령어를 사용하면 됩니다.</p>
</blockquote>
<h3 id="git-log"><code>git log</code></h3>
<ul>
<li>커밋의 목록을 볼 수 있음</li>
<li>커밋의 id, 시간, 커밋 메시지를 포함</li>
</ul>
<pre><code class="language-bash">git log</code></pre>
<pre><code class="language-bash">git shortlog</code></pre>
<ul>
<li>간략하게 <code>git log</code> 정보를 확인 가능 </li>
</ul>
<br />

<pre><code class="language-bash">git log --oneline</code></pre>
<ul>
<li><code>git shortlog</code> 보다는 더 많은 정보를 포함해서 확인 가능</li>
</ul>
<br>

<pre><code class="language-bash">git show &lt;commitId&gt;</code></pre>
<ul>
<li>특정 <code>&lt;commitId&gt;</code>를 이용해서 수정 내용을 확인할 수 있다.</li>
</ul>
<br>


<h3 id="git-diff"><code>git diff</code></h3>
<ul>
<li>모든 코드의 수정 내용을 알고 싶을 때 사용한다.</li>
</ul>
<p><code>git</code> 입장에서는 코드가 수정되면 기존 작성된 코드가 삭제되고 새로 작성된 코드가 추가되는 개념입니다.
그래서 기존의 작성된 코드가 수정됐다고 생각하지 않습니다.</p>
<br>


<pre><code class="language-bash">git diff &lt;fileName&gt;</code></pre>
<ul>
<li><code>fileName</code>의 수정 내용을 확인</li>
</ul>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/303cd280-cd24-4e97-a07c-953266b12a3b/image.png" alt=""></p>
<h2 id="git으로-협업하기-🤝"><code>git</code>으로 협업하기 🤝</h2>
<p>현재까지의 명령어는 지역 저장소에서 사용 가능합니다.
우리는 협업을 위해서는 <code>github</code>까지 사용해야 합니다.</p>
<h3 id="원격-저장소-연결">원격 저장소 연결</h3>
<pre><code class="language-bash">git remote add &lt;name&gt; &lt;url&gt;</code></pre>
<ul>
<li><code>name</code>이라는 이름으로 <code>url</code>을 연결 (<code>name</code>은 <code>url</code> 별칭을 의미한다.)</li>
<li><code>name</code>과 <code>url</code>은 필수</li>
</ul>
<br>

<pre><code class="language-bash">git remote add origin https://github.com/iamaiden/git-practice</code></pre>
<p>위와 같이 명령어를 사용할 수 있습니다.
<code>origin</code>이라는 <code>name</code>으로 <code>url</code>을 연결한다는 의미입니다.
이후에는 <code>url</code>에 대신에 <code>name</code>을 사용하면 됩니다. </p>
<h3 id="원격-저장소에-버전-내역-반영-git-push">원격 저장소에 버전 내역 반영 (<code>git push</code>)</h3>
<pre><code class="language-bash">git push &lt;name&gt; &lt;branch&gt;</code></pre>
<ul>
<li><code>git remote</code>를 하고나면 기본적으로 <code>master</code>라는 브랜치가 생성 됨</li>
<li><code>git push --help</code> 를 입력했을 때 대괄호([])에 나오는 명령어는 옵션</li>
<li><code>git push url별칭(ex. origin) url Branch(ex. master)</code></li>
</ul>
<br>

<pre><code class="language-bash">git push origin master</code></pre>
<p>지역 저장소의 <code>master</code> 브랜치의 버전 내역을 원격 저장소의 <code>master</code> 브랜치에 반영합니다.</p>
<h3 id="원격-저장소에서-내용-불러오기-git-pull">원격 저장소에서 내용 불러오기 (<code>git pull</code>)</h3>
<pre><code>git pull &lt;remote&gt; &lt;branch&gt;</code></pre><ul>
<li>협업 시 충돌을 막기 위해서 작업 전에 <code>git pull</code> 명령어로 시작</li>
</ul>
<br>


<pre><code class="language-bash">git pull origin master</code></pre>
<p>원격 저장소의 <code>master</code> 브랜치의 버전 내역을 로컬 저장소의 <code>master</code> 브랜치에 반영합니다.</p>
<h3 id="git-reset"><code>git reset</code></h3>
<ul>
<li>커밋을 초기화 시키고 싶을 때 사용</li>
</ul>
<pre><code class="language-bash">git reset HEAD~1
git reset --mixed HEAD~1</code></pre>
<p><code>HEAD</code>는 현재 커밋의 위치를 나타냅니다.
위의 명령어는 현재 커밋의 위치에서 한개의 커밋 내용을 뒤로 돌리는 의미를 가지고 있습니다.
두 명령어 모두 같은 기능을 수행합니다.</p>
<p>커밋 이후 해당 명령어를 사용하게 되면 파일들은 <code>modified</code> 상태로 변경됩니다. (<code>committed</code> → <code>modified</code>)</p>
<br>


<pre><code class="language-bash">git reset --soft HEAD~1</code></pre>
<p><code>--soft</code>라는 옵션을 추가하게 되면 파일들이 <code>staged</code> 상태로 변경됩니다. (<code>committed</code> → <code>staged</code>)</p>
<br>

<pre><code class="language-bash">git reset --hard &lt;commitId&gt;</code></pre>
<p><code>&lt;commitId&gt;</code> 이후 작성한 모든 커밋 내용을 삭제합니다.</p>
<br>


<pre><code class="language-bash">git reset --hard HEAD~1</code></pre>
<ul>
<li><code>committed</code> 상태를 수정 이전 혹은 생성 이전 상태로 변경 (<code>committed</code> → 기존 상태)</li>
<li><code>git reset HEAD~1</code> → <code>git restore &lt;fieName&gt;</code> 과정과 동일한 명령어 기능을 가지고 있다.</li>
</ul>
<p>이미 <code>github</code>에 올라간 내용을 되돌리기 위해선 어떻게 해야 할까요?</p>
<p><code>git reset</code> 명령어를 사용하게 되면 커밋 자체가 사라지기 때문에 되돌리려고 하는 내용을 다른 작업자가 알 수 없습니다.
그래서 되돌리는 내용도 표시할 수 있도록 <code>git revert</code> 명령어를 사용합니다.</p>
<h3 id="git-revert"><code>git revert</code></h3>
<ul>
<li>되돌리려고 하는 커밋을 그대로 유지하고, 새로운 커밋을 통해서 되돌리는 기능</li>
<li>보통 협업할 때 <code>revert</code> 명령어를 주로 사용한다.</li>
<li>되돌리려고 하는 내용을 공유하기 위해서 사용한다.</li>
</ul>
<pre><code class="language-bash">git revert HEAD</code></pre>
<pre><code class="language-bash">git revert &lt;commitId&gt;</code></pre>
<p>최근 커밋을 되돌리거나, <code>&lt;commitId&gt;</code> 를 통해서 커밋을 되돌릴 수 있습니다.</p>
<blockquote>
<p><code>revert</code> 명령어를 취소하는 것은 커밋을 되돌리는 것과 동일합니다.</p>
<p><code>git reset --hard HEAD~1</code> 명령어를 사용하면 됩니다.</p>
</blockquote>
<h3 id="git-branch"><code>git branch</code></h3>
<ul>
<li>보편적으로 <code>master</code> 브랜치가 전체 프로젝트의 중심이 된다.</li>
<li>신기능 등을 개발할 때 새로운 브랜치를 이용해서 신기능을 개발할 수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/s_sangs/post/4fc10975-77b6-48a2-aaba-98c8c8611b12/image.png" alt=""></p>
<p><code>git branch</code>라고 입력하게 되면 현재 존재하는 브랜치의 목록을 나타냅니다.</p>
<h4 id="브랜치-생성">브랜치 생성</h4>
<pre><code class="language-bash">git branch &lt;branch&gt;</code></pre>
<br>

<h4 id="브랜치-삭제">브랜치 삭제</h4>
<pre><code class="language-bash">git branch -d &lt;branch&gt;</code></pre>
<br>

<p>브랜치 이동</p>
<pre><code class="language-bash">git checkout &lt;branch&gt;</code></pre>
<ul>
<li>입력한 브랜치로 작업 공간을 이동한다.</li>
</ul>
<br>

<h4 id="브랜치를-나눠서-사용하는-이유">브랜치를 나눠서 사용하는 이유</h4>
<p>신기능을 개발하다가 운영 이슈 혹은 버그가 발생하게 되면, 브랜치를 나누지 않았을 경우 개발하던 신기능을 모두 되돌려야 합니다.</p>
<p>하지만 브랜치를 나눠서 사용하게 되면 운영에서 사용하고 있는 브랜치를 <code>master</code> 브랜치에 두고, 신기능을 개발하는 브랜치를 따로 생성해서 작업하게 되면 운영 이슈가 발생했을 때 브랜치 이동을 통해서 서로 코드의 간섭을 받지 않게 됩니다.</p>
<p>운영 이슈를 <code>master</code> 브랜치에서 해결하고 다시 본인의 브랜치에서 신기능 개발을 이어갈 수 있습니다.</p>
<p>그렇기 때문에 항상 작업을 시작할 때는 <code>git branch</code> 명령어를 통해서 현재 브랜치의 위치를 확인하는 습관을 들이는 것이 좋습니다.</p>
<p>추가적으로 <code>git pull origin &lt;branch&gt;</code> 명령어를 이용해서 다른 작업자들이 작업한 내용을 동기화하고 작업을 진행하는 것이 좋습니다.</p>
<h3 id="git-merge"><code>git merge</code></h3>
<ul>
<li>현재 브랜치에서 다른 브랜치의 변경 내역을 가져온다.</li>
</ul>
<pre><code class="language-bash">git merge &lt;branch&gt;</code></pre>
<br>

<p>만약 <code>develop</code> 브랜치에서 <code>master</code> 브랜치의 변경 내역을 가져오고 싶다면,
<code>git checkout develop</code> → <code>git merge master</code> 순서로 명령어를 입력하면 됩니다.
<code>merge</code> 과정을 포기하고 싶다면 <code>git merge --abort</code> 명령어를 입력하면 됩니다.</p>
<h3 id="git-rebase"><code>git rebase</code></h3>
<ul>
<li>현재 브랜치에 다른 브랜치의 변경 내역을 가져오면서 <code>base</code>를 재설정한다.</li>
</ul>
<pre><code class="language-bash">git rebase &lt;branch&gt;</code></pre>
<br>

<p><code>git merge</code>의 경우에는 현재 브랜치에 다른 브랜치의 변경 내역을 가져오면서 새로운 커밋이 발생하게 되는데, <code>git rebase</code>의 경우에는 현재 브랜치와 다른 브랜치의 변경 내역을 시간 순서대로 반영하고, 새로운 커밋이 발생하지 않습니다.</p>
<p>하지만 많은 작업자들이 사용하는 브랜치의 경우 <code>rebase</code> 명령어를 사용하는 것은 위험합니다.</p>
<p>기존 작업자들의 커밋 히스토리가 변경되는 경우에는 각 작업자들은 떄에 따라 자신의 커밋을 다시 반영하거나 재작업을 해야할 수도 있습니다.</p>
<p><code>git rebase</code> 진행 중 <code>confilct</code>가 발생하는 경우, <code>git rebase --continue</code> 명령어를 입력하면 됩니다.</p>
<p><code>rebase</code> 과정을 포기하고 싶다면 <code>git rebase --abort</code> 명령어를 입력하면 됩니다.</p>
<h4 id="conflict가-발생했을-경우"><code>conflict</code>가 발생했을 경우</h4>
<p><code>git merge</code>나 <code>git pull</code>, <code>git rebase</code> 와 같은 명령어를 사용하다보면 <code>conflict</code>가 발생할 수 있습니다.</p>
<p>다른 작업자와 같은 코드를 수정하게 되서 나타나는 <strong>&quot;충돌&quot;</strong>입니다.</p>
<p>이러한 경우 우선적으로 해당 코드 내용을 수정합니다.</p>
<p>수정하지 않고 파일을 추가, 커밋, 푸시하게 되면 <code>conflict</code>가 발생한 부분은 각 브랜치에서 들어온 내용을 모두 반영하게 됩니다.</p>
<p>수정이 완료 됐다면 해당 파일을 <code>add</code> → <code>commit</code> → <code>push</code> 합니다.</p>
<pre><code class="language-bash">git commit -am &lt;commitMessage&gt;
git push origin &lt;branch&gt;</code></pre>
<h3 id="git-cherry-pick"><code>git cherry-pick</code></h3>
<ul>
<li>다른 브랜치의 변경 내역을 가져오고 싶은 경우에 대부분 <code>rebase</code>, <code>merge</code> 명령어를 사용한다.</li>
<li>특정 변경 내역을 가져오고 싶을 때 <code>cherry-pick</code> 명령어를 사용한다.</li>
</ul>
<h4 id="1개의-커밋을-적용">1개의 커밋을 적용</h4>
<pre><code class="language-bash">git cherry-pick &lt;commitId&gt;</code></pre>
<br>


<h4 id="1개-이상의-커밋을-적용">1개 이상의 커밋을 적용</h4>
<pre><code class="language-bash">git cherry-pick &lt;commitId&gt; &lt;commitId&gt;</code></pre>
<br>


<h4 id="범위를-이용해서-커밋을-적용">범위를 이용해서 커밋을 적용</h4>
<pre><code class="language-bash">git cherry-pick &lt;commitId&gt;..&lt;commitId&gt;</code></pre>
<p>앞에 입력한 <code>&lt;commitId&gt;</code> 부터 뒤에 입력한 <code>&lt;commitId&gt;</code> 이전의 모든 커밋을 적용합니다.</p>
<h3 id="git-stash"><code>git stash</code></h3>
<ul>
<li>어느 브랜치에서 수정 작업을 진행하던 중 다른 브랜치로 이동하고 싶을 때 사용한다.</li>
<li>보통 작업을 진행하던 중 다른 브랜치로 이동하게 되면 에러가 발생하게 된다.</li>
<li>임시 저장소를 생성해서 해당 작업 내용을 저장한 뒤 브랜치를 이동한다.</li>
</ul>
<h4 id="임시-저장소-생성">임시 저장소 생성</h4>
<pre><code class="language-bash">git stash</code></pre>
<ul>
<li>작업 중인 내용이 임시 저장소에 저장이 되고, 현재 브랜치에는 수정 사항이 없어지게 된다.</li>
<li>이후 <code>git checkout</code> 명령어를 사용해서 다른 브랜치로 이동할 수 있다.</li>
</ul>
<br>

<h4 id="임시-저장소-목록">임시 저장소 목록</h4>
<pre><code class="language-bash">git stash list</code></pre>
<ul>
<li>저장된 내용을 목록으로 확인할 수 있다. 최근에 추가된 내용이 0번으로 추가된다.</li>
</ul>
<br>

<h4 id="저장-내용-반영">저장 내용 반영</h4>
<pre><code class="language-bash">git stash apply</code></pre>
<ul>
<li>저장 내용을 현재 브랜치에 반영한다.</li>
</ul>
<br>

<h4 id="임시-저장소-삭제">임시 저장소 삭제</h4>
<pre><code class="language-bash">git stash drop</code></pre>
<ul>
<li><p><code>git stash apply</code> 명령어를 사용하게 되는 경우 저장 내용은 반영하지만, 임시 저장소에 해당 내용이 삭제 되지는 않는다.</p>
</li>
<li><p>저장 내용 반영과 저장소 삭제를 동시에 진행하고 싶다면, <code>git stash pop</code> 명령어를 사용하면 된다.</p>
</li>
</ul>
<p><code>git stash</code> 명령어를 유용하게 사용하는 경우는 브랜치를 착각했을 때입니다.</p>
<p><code>develop</code> 브랜치에서 작업해야 되는 기능을 브랜치를 확인하지 않고 <code>master</code> 브랜치에서 작업했다고 생각해봅시다.</p>
<p>이러한 경우에는 작업한 내용이 크지 않다면, 수정 사항을 <code>git restore</code>  명령어를 통해서 되돌리고 브랜치를 이동할 수 있습니다.</p>
<p>하지만 작업 내용이 많다면 이렇게 하기 쉽지 않을 것 입니다. 이러한 경우에는</p>
<pre><code class="language-bash">git stash
git checkout develop
git stash pop</code></pre>
<p>위와 같이 명령어를 입력하게 되면 모든 수정 사항이 <code>develop</code> 브랜치로 이동됩니다.</p>
<p><code>git stash pop</code> 명령어를 사용했을 때, <code>conflict</code>가 발생하게 될 수 있습니다. 이러한 경우에는 동일하게 수정하고 반영하면 됩니다.</p>
<h2 id="마무리">마무리</h2>
<p>하나하나의 명령어는 조금 더 자세한 설명을 찾아봐야 되겠지만, 정리한 명령어를 가지고 <code>git</code>을 사용하시는데는 큰 문제가 없을거라고 생각합니다!</p>
<p>언젠가는 <code>git</code>에 대해서 잘 정리해놓고 싶은 생각이 있었는데 이렇게라도 정리를 하게 되서 뿌듯합니다. 👍</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://ko.wikipedia.org/wiki/%EA%B9%83%ED%97%88%EB%B8%8C">https://ko.wikipedia.org/wiki/%EA%B9%83%ED%97%88%EB%B8%8C</a></li>
<li><a href="https://velog.io/@donghoim/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EC%82%B0%EC%97%85%EA%B8%B0%EC%82%AC-36%EA%B0%95-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC-%EB%8F%84%EA%B5%AC">https://velog.io/@donghoim/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EC%82%B0%EC%97%85%EA%B8%B0%EC%82%AC-36%EA%B0%95-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC-%EB%8F%84%EA%B5%AC</a></li>
<li><a href="https://cross-the-line.tistory.com/m/20">https://cross-the-line.tistory.com/m/20</a></li>
<li><a href="https://www.youtube.com/watch?v=cEg9hiZax8U&amp;list=PLcqDmjxt30RvjqpIBi4mtkK5LkzYtXluF">https://www.youtube.com/watch?v=cEg9hiZax8U&amp;list=PLcqDmjxt30RvjqpIBi4mtkK5LkzYtXluF</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript enum에 대해서]]></title>
            <link>https://velog.io/@s_sangs/TypeScript-enum%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-l01bmzv8</link>
            <guid>https://velog.io/@s_sangs/TypeScript-enum%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-l01bmzv8</guid>
            <pubDate>Thu, 27 Apr 2023 22:13:02 GMT</pubDate>
            <description><![CDATA[<p><code>enum</code>을 사용하던 와중 우연히 <code>enum</code>을 사용하면 안된다라는 포스팅을 본 적이 있습니다.
하지만 왜 <code>enum</code>을 사용하면 안되는지에 대해서는 자세하게 알지 못했습니다.</p>
<p>오늘은 <em>꼭 <code>enum</code>을 사용하면 안되는 것인가..?</em> 에 대해서 자세하게 알아보려고 합니다.
제가 속한 조직에서는 <code>enum</code>을 선택해서 사용했는데요!
결론적으로 <code>enum</code>을 선택해서 사용한 의견에 대해서도 알아보려고 합니다.</p>
<h2 id="enum">enum</h2>
<p><code>enum</code>은 열거형 변수로 정수를 하나로 합칠 때 편리한 기능입니다.
임의의 숫자나 문자열을 할당할 수 있으며 하나의 유형으로 사용해서 버그를 줄일 수 있습니다.</p>
<pre><code class="language-typescript">// 아무것도 지정하지 않은 경우에는 0부터 숫자를 매깁니다. 
enum MOBILE_OS {
  IOS, // 0
  ANDROID // 1
}

// 임의의 숫자나 문자열을 할당할 수도 있습니다
enum MOBILE_OS {
  IOS = &#39;iOS&#39;,
  ANDROID = &#39;Android&#39;
}</code></pre>
<blockquote>
<p><code>enum</code>은 타입스크립트가 자체적으로 구현하는 기능입니다.</p>
</blockquote>
<h2 id="enum과-트리-쉐이킹-tree-shaking">enum과 트리 쉐이킹 (Tree-shaking)</h2>
<p><code>enum</code>을 사용하지 않는 것을 권장하는 것 중 제일 큰 이유가 <code>tree-shaking</code>입니다.</p>
<h3 id="tree-shaking이란">Tree-shaking이란?</h3>
<ul>
<li>사용하지 않는 코드를 삭제하는 기능</li>
<li>번들 크기를 줄여 페이지가 표시되는 시간을 단축할 수 있다.</li>
</ul>
<p><code>enum</code>을 사용하게 되면 <code>tree-shaking</code>이 되지 않습니다.
왜냐하면 타입스크립트가 자체적으로 구현했기 때문에 타입스크립트는 자바스크립트로 변환할 때 <code>IIFE</code>(즉시 실행 함수)를 포함한 코드를 생성합니다.</p>
<p>하지만 <code>rollup</code>과 같은 번들러는 <code>IIFE</code>를 사용하지 않는 코드라고 판단할 수 없어서 <code>tree-shaking</code>이 되지 않습니다.
결과적으로 사용하지 않는 코드들도 최종 번들에는 포함되어 있습니다.</p>
<h2 id="enum과-enum을-대체할-수-있는-것">enum과 enum을 대체할 수 있는 것</h2>
<ul>
<li>enum</li>
<li>const enum</li>
<li>Union Types</li>
</ul>
<h3 id="enum-1">enum</h3>
<pre><code class="language-typescript">enum CountryCode1 {
  &#39;Argentina&#39; = &#39;AR&#39;,
  &#39;China&#39; = &#39;CN&#39;,
  &#39;Korea&#39; = &#39;KR&#39;,
}</code></pre>
<p><strong>장점</strong></p>
<ol>
<li><code>key</code> 값에 의미 있는 값을 부여할 수 있습니다.</li>
<li>타입에 enum을 지정하면 따로 <code>key</code>에 대한 타입을 만들지 않아도 돼서 편리합니다.</li>
<li><code>Object.keys</code>, <code>Object.entries</code>를 이용해서 값들에 대한 순회가 편리합니다.
(<code>number</code>타입의  <code>value</code> 사용하지 않을 때)</li>
<li><code>enum</code>을 쓰는 쪽에서는 오타를 낼 확률이 0%가 됩니다. 무조건 <code>enum</code> 값으로 써야 하기 때문입니다.(<code>number</code>타입의  <code>value</code> 사용하지 않을 때)</li>
<li><code>value</code>가 <code>number</code> 형일 때, 양방향 매핑이 가능합니다.</li>
</ol>
<p><strong>단점</strong></p>
<ol>
<li><code>tree-shaking</code>이 되지 않습니다.</li>
<li>자바스크립트로 변환되고 나면 비교적 용량이 커집니다.</li>
<li><code>number</code>타입의 <code>value</code>가 있다면 문제가 발생합니다.</li>
<li><code>value</code>가 <code>number</code> 형일 때, 양방향 매핑이 가능합니다.</li>
</ol>
<h3 id="const-enum">const enum</h3>
<pre><code class="language-typescript">const enum CountryCode2 {
  &#39;Argentina&#39; = &#39;AR&#39;,
  &#39;China&#39; = &#39;CN&#39;,
  &#39;Korea&#39; = &#39;KR&#39;,
}</code></pre>
<p><strong>장점</strong></p>
<ol>
<li><code>tree-shaking</code>이 됩니다.</li>
<li>자바스크립트로 변환되고 나면, 매우 적은 용량을 차지합니다.</li>
<li><code>key</code> 값에 의미 있는 값을 부여할 수 있습니다.</li>
<li><code>enum</code>을 쓰는 쪽에서는 오타를 낼 확률이 0%가 됩니다. 무조건 <code>enum</code> 값으로 써야 하기 때문입니다.(<code>number</code>타입의  <code>value</code> 사용하지 않을 때)</li>
</ol>
<p><strong>단점</strong></p>
<ol>
<li><code>Object.keys</code>, <code>Object.entries</code>를 이용해서 값들에 대해 순회를 할 수가 없습니다.</li>
<li><code>–isolatedModules</code> 옵션을 사용하면, 사용 불가합니다.</li>
<li>타입스크립트 패키지를 만들고, 이를 다른 곳에서 사용한다면, 이를 타입용으로 사용할 수가 없습니다.</li>
<li><code>CRA</code>, <code>Next.js</code>에서 사용 불가합니다.</li>
<li><code>babel</code> 설정도 추가로 필요합니다.</li>
</ol>
<h3 id="union-types">Union Types</h3>
<pre><code class="language-typescript">const CountryCode3 = {
  &#39;Argentina&#39;: &#39;AR&#39;,
  &#39;China&#39;: &#39;CN&#39;,
  &#39;Korea&#39;: &#39;KR&#39;,
} as const

type CountryCode3Type = typeof CountryCode3[keyof typeof CountryCode3]  // 이렇게 별도의 union type을 지정해줘야 함</code></pre>
<p><strong>장점</strong></p>
<ol>
<li><code>tree-shaking</code>이 됩니다.</li>
<li>자바스크립트로 변환되고 나면, 매우 적은 용량을 차지합니다.</li>
<li><code>Object.keys</code>, <code>Object.entries</code>를 이용해서 값들에 대한 순회가 편리합니다.</li>
<li><code>key</code> 값에 의미 있는 값을 부여할 수 있습니다.</li>
</ol>
<p><strong>단점</strong></p>
<ol>
<li>이것을 위한 별도의 <code>union type</code>을 만들어야 해서, 성가십니다.</li>
<li>원래의 의도가 <code>enum</code>과는 다르기 때문에, 쓰기가 약간은 망설여집니다.</li>
</ol>
<h2 id="결론-👨⚖️">결론 👨‍⚖️</h2>
<p>대부분의 <code>enum</code>을 사용하지 않는 것을 권장하는 이유는 <code>tree-shaking</code>이었습니다!
하지만 저는 우아한형제들이 고민한 <code>enum</code>에 대한 의견에 조금 더 공감이 됐습니다.</p>
<h3 id="우아한-형제들이-enum을-선택한-이유">우아한 형제들이 <code>enum</code>을 선택한 이유</h3>
<ul>
<li><code>tree-shaking</code>이 되지 않는다고 해도, <code>enum</code> 선언부가 엄청나게 크지 않는 이상, 이런 정도의 용량 다이어트가 필요한지 의문이다.</li>
<li>번들러마다 <code>tree-shaking</code>이 가능하기도 하다. (<code>rollup</code>은 불가능, <code>vite</code>는 가능)</li>
<li>다른 대안에 대한 단점이 부각되어 보이고, 최종적으로 <code>enum</code>을 쓰되, <code>enum</code>의 단점을 최소화하고 장점을 극대화시키기 위해서 <code>value</code>는 <code>string</code>형으로 사용한다.</li>
</ul>
<p>정도가 될 것 같습니다!</p>
<p>위의 설명된 이유에 추가적으로 오타가 날 확률이 없다는 것도 저한테는 매우 매력적인 장점이라고 생각했습니다.
조금 더 자세한 설명을 확인하고 싶다면 하단의 출처를 확인해주세요!</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking/">https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking/</a></li>
<li><a href="https://techblog.woowahan.com/9804/">https://techblog.woowahan.com/9804/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[정말 리얼 마지막 ESLint 사용법 뿌시기]]></title>
            <link>https://velog.io/@s_sangs/%EC%A0%95%EB%A7%90-%EB%A6%AC%EC%96%BC-%EB%A7%88%EC%A7%80%EB%A7%89-ESLint-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%BF%8C%EC%8B%9C%EA%B8%B0</link>
            <guid>https://velog.io/@s_sangs/%EC%A0%95%EB%A7%90-%EB%A6%AC%EC%96%BC-%EB%A7%88%EC%A7%80%EB%A7%89-ESLint-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%BF%8C%EC%8B%9C%EA%B8%B0</guid>
            <pubDate>Thu, 27 Apr 2023 11:35:07 GMT</pubDate>
            <description><![CDATA[<p>오늘은 <code>eslint</code>에 대해서.. 정말 마지막으로 ESLint에 대해서 뿌셔보려고 합니다..!</p>
<p>그래도 이전에 <code>@typescript-eslint</code>나 <code>styleslint</code> 등을 사용하면서 <code>eslint</code>를 그래도 잘 사용하고 있다고 생각하고 있었는데요!
매번 사용을 할 때마다 계속 헷갈려하는 제 모습을 보고.. 이해를 못하고 있다고 생각이 들었습니다.</p>
<p>매번 적용을 하다보면 궁금해 하는 질문은 공통적이었습니다.</p>
<ol>
<li><code>eslint-config</code>와 <code>eslint-plugin</code>의 제대로 된 차이점은 무엇인가?</li>
<li><code>extends</code>, <code>rule</code>, <code>recommended</code>는 어떻게 해석하는가?</li>
<li><code>.eslintrc.js</code> 파일은 어떤 방식으로 작성해야 하는가?</li>
</ol>
<p>이렇게 적고보니.. 그냥 아예 <code>lint</code>를 모르는 사람 같았습니다.. 🤦‍♂️
그래서 오늘은 다시 한 번 정리와 함께 더 이상의 이론은 공부하지 않겠다는 다짐으로 작성해보려고 합니다.</p>
<h2 id="eslint란"><code>eslint</code>란?</h2>
<ul>
<li>자바스크립트 코드에서 문제를 찾아주고 고쳐주는 정적 분석 도구</li>
<li>기본적으로 CRA로 리액트 프로젝트를 생성하게 되면 <code>eslint-config-react-app</code>이라는 설정이 세팅되어 있다.</li>
</ul>
<p><code>정적 분석 도구</code>... 정말 많이 들었던 것 같습니다.. ㅎ
그리고 CRA 과정에서 <code>eslint</code> 관련된 라이브러리가 설치 된다는 것을 처음 알았습니다.</p>
<h2 id="plugin과-config"><code>plugin</code>과 <code>config</code></h2>
<p>사실 <code>eslint</code>를 사용하면서 가장 구분이 잘 되지 않고, 제대로 이해하기 어려웠던 부분이었습니다.</p>
<p>예를 들면 <code>eslint-plugin-import</code>, <code>eslint-config-prettier</code>, <code>eslint-plugin-prettier</code> 이런식으로 점점 추가해서 사용하라고 이야기하는데.. 추가하면 할수록 뭐가 뭔지 점점 헷갈리게 됩니다.</p>
<p>오늘은 확실하게 구분지어서 개념을 정리해보겠습니다. 🪓</p>
<h3 id="eslint-plugin-"><code>eslint-plugin-*</code></h3>
<p>짧게 플러그인이라고 하겠습니다.</p>
<p>플러그인 패키지는 <strong>룰을 정리한 패키지</strong>입니다.
예를 들면 <code>eslint-plugin-react</code>라는 패키지는 리액트와 관련된 룰을 정의한 패키지입니다.</p>
<p>그렇다면 사용은 어떻게 할까요?</p>
<pre><code class="language-json">{
    &quot;plugins&quot;: [&quot;react&quot;]
}</code></pre>
<p><code>eslint</code> 설정을 할 때 흔히 보던 명칭입니다.
하지만 이렇게 작성하면 아무런 동작을 하지 않습니다.. 🤯
위의 의미는 &quot;나는 이제 <code>eslint-plugin-react</code>를 추가할거야!&quot; 라고 하는 것과 동일합니다.</p>
<p>선언만하고 사용은 하지 않은 것이죠..
그러면 해당 패키지를 사용하려면 어떻게 해야할까요?
<code>rules</code>에서 관리를 해줘야 합니다.</p>
<pre><code class="language-json">{
    &quot;plugins&quot;: [&quot;react&quot;],
    &quot;rules&quot;: {
        &quot;react/jsx-uses-react&quot;: error
    }
}</code></pre>
<p>이런식으로 해당 플러그인에 대한 룰(규칙)을 직접 입력해서 사용할 수 있습니다.</p>
<p>하지만 이렇게 플러그인을 사용하려면 매번 모든 플러그인의 룰을 알고 있어야하고, 활용할 줄 알아야합니다.
그리고 사용할 모든 룰을 직접 작성해줘야 합니다.</p>
<p>하나의 플러그인만 사용한다면 모를까 대부분의 사람들은 여러 플러그인을 설치해서 사용합니다.
사실상 모든 룰을 다 숙지한다는 것은 매우 어렵습니다.</p>
<p>그렇기 때문에 대부분의 플러그인은 자체 설정을 제공합니다.
그 자체 설정이 <code>recommended</code>, <code>strict</code>, <code>all</code> 과 같은 단어입니다.</p>
<p>해당 플러그인에서 제공하는 자체 설정을 사용하려면</p>
<pre><code class="language-json">{
    &quot;extends&quot;: [&quot;plugin:react/recommended&quot;]
}</code></pre>
<p>위와 같은 코드로 작성해줘야 합니다.
흔히 보던 <code>recommended</code>라는 키워드가 나왔습니다.</p>
<p>그렇다면 여기서 궁금증이 생길 수 있습니다.</p>
<p><em>자체 설정은 뭐고.. 좀전에 플러그인은 <code>plugins</code> 안에서 사용한다고 했는데.. 왜 <code>extends</code>라는 영역에서 사용하는거지?</em> 🤔</p>
<h3 id="플러그인의-자체설정-recommended-all-strict-등">플러그인의 자체설정 (<code>recommended</code>, <code>all</code>, <code>strict</code> 등)</h3>
<p>자체 설정은 플러그인에서 룰에 대한 세팅을 해놓고 제공하는 것을 의미합니다.
그리고 해당 플러그인에서 제공하는 자체 설정의 경우에는 <code>extends</code> 영역에서 사용해야 합니다.
(하지만 왜 <code>extends</code> 영역에서 사용해야 되는지는.. 잘모르겠습니다.. 🥲)</p>
<pre><code class="language-javascript">// eslint-plugin-react/configs/recommended
&#39;use strict&#39;;

const all = require(&#39;./all&#39;);

module.exports = Object.assign({}, all, {
  languageOptions: all.languageOptions,
  rules: {
    &#39;react/display-name&#39;: 2,
    &#39;react/jsx-key&#39;: 2,
    &#39;react/jsx-no-comment-textnodes&#39;: 2,
    &#39;react/jsx-no-duplicate-props&#39;: 2,
    &#39;react/jsx-no-target-blank&#39;: 2,
    &#39;react/jsx-no-undef&#39;: 2,
    &#39;react/jsx-uses-react&#39;: 2,
    &#39;react/jsx-uses-vars&#39;: 2,
    &#39;react/no-children-prop&#39;: 2,
    &#39;react/no-danger-with-children&#39;: 2,
    &#39;react/no-deprecated&#39;: 2,
    &#39;react/no-direct-mutation-state&#39;: 2,
    &#39;react/no-find-dom-node&#39;: 2,
    &#39;react/no-is-mounted&#39;: 2,
    &#39;react/no-render-return-value&#39;: 2,
    &#39;react/no-string-refs&#39;: 2,
    &#39;react/no-unescaped-entities&#39;: 2,
    &#39;react/no-unknown-property&#39;: 2,
    &#39;react/no-unsafe&#39;: 0,
    &#39;react/prop-types&#39;: 2,
    &#39;react/react-in-jsx-scope&#39;: 2,
    &#39;react/require-render-return&#39;: 2,
  },
});

// this is so the `languageOptions` property won&#39;t be warned in the new config system
Object.defineProperty(module.exports, &#39;languageOptions&#39;, { enumerable: false });</code></pre>
<p>위와같이 <code>recommended</code> 설정에는 직접 입력해야하는 룰들이 이미 입력이 되어있습니다.
그리고 이미 플러그인을 포함하고 있습니다.</p>
<p>하지만 <code>plugins</code>이 안 보이실겁니다..!
그 이유는 <code>all</code> 자체 설정에서 플러그인을 포함하고 있고 해당 설정을 불러와서 다시 로직을 처리하기 때문에 <code>plugins</code> 영역을 <code>recommended</code> 설정에서 찾을 수 없습니다!</p>
<p>위의 코드를 보면 <code>all</code> config 설정을 불러와서 <code>Object.assign()</code> 함수를 통해서 <code>recommended</code> config 설정을 하는 모습을 볼 수 있습니다.</p>
<h3 id="eslint-config-"><code>eslint-config-*</code></h3>
<p>그렇다면 config 패키지는 무엇일까요? 😁</p>
<p><code>eslint-plugin</code> 패키지들이나 룰들을 모아서 설정으로 만든 것이 <code>eslint-config-*</code> 패키지입니다.</p>
<p><code>eslint</code>에 관심이 있으시다면 많은 분들이 보셨던 <code>eslint-config-airbnb</code> 패키지를 예를 들 수 있습니다.
<code>eslint-config-airbnb</code> 패키지 내부에는 아래의 플러그인과 룰들을 조합해서 만든 설정 패키지입니다.</p>
<ul>
<li><code>eslint</code></li>
<li><code>eslint-plugin-import</code></li>
<li><code>eslint-plugin-react</code></li>
<li><code>eslint-plugin-react-hooks</code></li>
<li><code>eslint-plugin-jsx-a11y</code></li>
</ul>
<pre><code class="language-json">{
    &quot;extends&quot;: [&quot;airbnb&quot;]
}</code></pre>
<p>사용할 때는 위와 같이 간단하게 사용할 수 있습니다.</p>
<h2 id="parser"><code>parser</code></h2>
<p>대부분 저처럼 <code>eslint-plugin</code>이나 <code>eslint-config</code>에 빠져서 지나치는 경우가 있습니다.</p>
<p><code>parser</code>는 무엇일까요?
코드를 분석하기 위한 파싱 툴입니다.
기본 값은 <code>espree</code> 입니다. 오늘은 <code>parser</code>에 대해서는 자세하게 다루지는 않으려고 합니다..!</p>
<p>보통 자바스크립트에서는 <code>@babel/eslint-parser</code>를 사용합니다.
타입스크립트에서는 <code>@typescript-eslint/parser</code>를 사용합니다.</p>
<p>이번에 알게 된 사실인데 아래처럼 <code>recommended</code> 자체 설정을 사용하게 되면 <code>@typescript-eslint/parser</code>가 자동적으로 포함됩니다..!</p>
<pre><code class="language-json">{
    extends: [&quot;plugin:@typescript-eslint/recommended&quot;]
}</code></pre>
<pre><code class="language-javascript">// typescript-eslint/packages/eslint-plugin/src/config/base.ts

export = {
  parser: &#39;@typescript-eslint/parser&#39;,
  parserOptions: { sourceType: &#39;module&#39; },
  plugins: [&#39;@typescript-eslint&#39;],
};</code></pre>
<p>순간 <code>@typescript-eslint</code>조차도 <code>plugin</code>이라고 생각했던.. 저를 반성하며.. 🤦‍♂️
<code>@typescript-eslint</code>는 <code>parser</code>도 있고 플러그인도 있고, 자체 설정도 포함되어 있었던 것이죠.. ㅎ</p>
<h2 id="정리">정리</h2>
<h3 id="eslint-plugin"><code>eslint-plugin</code></h3>
<ul>
<li><code>eslint</code>에 대한 룰만 정의한 패키지이다. (아직 사용한다고 말 안했다.)</li>
<li><code>eslint</code> 설정 파일의 <code>plugins</code>, <code>extends</code> 영역에서 사용 가능하다.</li>
<li>기본적으로 커스텀한 규칙을 모아서 제공하기 위해 만들어진다.</li>
<li>자체 설정(<code>config</code>)을 사용하지 않는다면 개인적으로 룰을 숙지하고 설정해줘야 한다.</li>
<li>자체 설정은 <code>extends</code> 영역에서 <code>plugin:패키지이름/config이름</code>으로 사용해야 한다.</li>
<li>자체 설정은 어떤 룰을 사용할 것인지도 설정이 되어 있고, 이미 <code>eslint-plugin</code>도 포함되어 있다.</li>
<li>네이밍은 기본적으로 <code>eslint-plugin-*</code>, <code>@&lt;scope&gt;/eslint-plugin</code>, <code>@&lt;scope&gt;/eslint-plugin-*</code> 식으로 사용할 수 있다.</li>
<li>플러그인의 환경 설정, 플러그인의 프로세서, 복수 개의 config를 포함할 수 있다.</li>
</ul>
<h3 id="eslint-config"><code>eslint-config</code></h3>
<ul>
<li><code>eslint-plugin</code> 패키지들과 룰을 모아서 설정으로 만든 패키지이다.</li>
<li>일반적으로 <code>eslint</code> 설정 파일들을 공유하기 위한 목적으로 만들어진다.</li>
<li><code>eslint</code> 설정 파일의 <code>extends</code> 영역에서 사용해야 한다.</li>
<li>플러그인의 경우에는 자체 설정을 사용하려면 <code>extends</code> 영역에서 <code>plugin:패키지이름/config이름</code>으로 사용해야 하는데 <code>eslint-config</code>는 패키지 이름만 써주면 된다.</li>
<li>네이밍은 기본적으로 <code>eslint-config-*</code>, <code>@&lt;scope&gt;/eslint-config</code>, <code>@&lt;scope&gt;/eslint-config-*</code> 식으로 사용할 수 있다.</li>
</ul>
<p><em>자신만의 규칙도 만들고 설정도 만들고 싶다면 <code>eslint-plugin</code>을 사용하거나 만드는 것을 추천합니다. 하지만 <code>airbnb</code>처럼 기존의 설정들을 모아서 공유하려는 목적이 강하다면 <code>eslint-config</code>를 사용하거나 만드는 것을 추천합니다.</em></p>
<h2 id="마무리">마무리</h2>
<p>다양한 <code>eslint-plugin</code>이나 <code>eslint-config</code> 패키지들에 관심을 가지면서 이렇게 정리를 해보게 되었습니다.
알고 쓰는 것과 모르고 쓰는 것의 차이는 크다고 생각합니다.
앞으로는 과거보다는 더 잘 알고 쓴다는 생각에 조금 더 뿌듯하긴 합니다. 😎</p>
<p>그리고 사용하다보니 불편한 점도 있었고, 커스텀해보고 싶다는 생각도 들었습니다.</p>
<p>시간이 될 때 개인적으로 <code>eslint-plugin</code>, <code>eslint-config</code> 패키지 하나씩 만들어 보려고 합니다.
개인적으로 프로젝트 만들때마다 설정하는 것도 귀찮기도하고.. 회사에서 협업용으로 하나 만들어서 가져가보려고 합니다!</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://github.com/jsx-eslint/eslint-plugin-react/blob/master/index.js">https://github.com/jsx-eslint/eslint-plugin-react/blob/master/index.js</a></li>
<li><a href="https://github.com/jsx-eslint/eslint-plugin-react/blob/master/configs/recommended.js">https://github.com/jsx-eslint/eslint-plugin-react/blob/master/configs/recommended.js</a></li>
<li><a href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/base.ts">https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/base.ts</a></li>
<li><a href="https://velog.io/@yrnana/ESLint-%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90">https://velog.io/@yrnana/ESLint-%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90</a></li>
<li><a href="https://younho9.dev/sharing-eslint-config">https://younho9.dev/sharing-eslint-config</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript $(dollor)와 _(underScore) 의미]]></title>
            <link>https://velog.io/@s_sangs/JavaScript-dollor-underScore</link>
            <guid>https://velog.io/@s_sangs/JavaScript-dollor-underScore</guid>
            <pubDate>Thu, 27 Apr 2023 10:14:18 GMT</pubDate>
            <description><![CDATA[<h1 id="javascript-dollor와-_underscore-의미">JavaScript $(dollor)와 _(underScore) 의미</h1>
<p>오늘은 <code>$</code>와 <code>_</code>의 의미를 자세하게 알아보려고 합니다.
이전에 제이쿼리를 사용하면서 <code>$</code>는 자주 볼 수 있었는데요.
<code>_</code>는 조금 생소하기도 하고, 정확한 의미를 정리해두는 게 좋을 것 같아서 내용을 찾아 보았습니다.</p>
<p>요즘 많은 부분에서 공부가 필요하다고 느낍니다.. 😂</p>
<p><code>$</code>와 <code>_</code>는 둘 다 자바스크립트의 식별자입니다.
식별자는 이름과 같은 방식으로 객체를 식별한다는 의미를 가지고 있습니다.
여기서 객체는 변수, 함수, 속성, 이벤트 및 객체 등이 포함됩니다.</p>
<p><code>$</code>와 <code>_</code>는 다른 특수기호와 같은 방식으로 처리되지 않습니다.
대신 알파벳 문자처럼 취급됩니다.
그리고 두 식별자 모두 강요가 아닌 일종의 관례로 사용되고 있습니다.
<code>$</code>, <code>_</code>의 후속 문자에는 숫자도 포함될 수 있습니다.</p>
<h2 id="doller-식별자">$(doller) 식별자</h2>
<p><code>$</code> 식별자의 용도는 크게 2가지로 나눌 수 있습니다.</p>
<ul>
<li><code>document.getElementById()</code> 함수의 바로가기</li>
<li>템플릿 스트링</li>
</ul>
<p><code>$</code> 식별자는 일반적으로 <code>document.getElementById()</code> 함수의 바로가기로 사용됩니다.
함수의 이름이 매우 길고 자주 사용되기 때문에 바로 가기로 사용 됐습니다.</p>
<blockquote>
<p> <code>document.getElementById()</code> 함수는 <code>HTML</code> 요소에서 <code>id</code>를 알아내는 함수입니다.</p>
</blockquote>
<p><code>$</code> 식별자를 사용할 때는 별도의 라이브러리를 사용하지 않아도 됩니다.
하지만 <code>$</code>를 <code>document.getElementById()</code> 함수의 바로가기로 사용하기 위해서는 별도의  <code>$()</code> 함수 정의가 필요합니다.</p>
<pre><code class="language-javascript">function $(id) {
  return document.getElementById(id);
}</code></pre>
<pre><code class="language-html">&lt;div id=&quot;myDiv&quot;&gt;
  Hello World!!
&lt;/div&gt;</code></pre>
<pre><code class="language-javascript">const element = $(myDiv); // == document.getElementById(&#39;myDiv&#39;)</code></pre>
<p><code>$()</code> 함수가 정의되고 나면 위와 같이 사용할 수 있습니다.
추가적으로 <code>$</code> 식별자를 이용해서 템플릿 스트링으로 사용할 수 있습니다.
백틱을 사용할 때 <code>$</code> 식별자를 이용해서 변수명을 그대로 보여줄 수도 있습니다.</p>
<pre><code class="language-javascript">const name = &quot;aiden&quot;;
const age = 20;

console.log(`이름은 ${name}이고, 나이는 ${age}입니다.`)</code></pre>
<p>바닐라 자바스크립트, 제이쿼리를 거쳐서 리액트를 사용하고 난 뒤부터는 아무래도 <code>$</code> 식별자를 사용하는 일이 매우 줄어든 것 같습니다.</p>
<p>그나마 템플릿 리터럴에 많이 사용했던 것 같네요 😁</p>
<h2 id="_underscore-식별자">_(underScore) 식별자</h2>
<p><code>_</code> 식별자는 변수나 함수 앞에 접근제어자 <code>private</code> 특성이 적용되어야 될 때 명시하는 역할로 사용됐습니다.
그래서 <code>public</code>과 <code>private</code>를 즉시 식별할 수 있는 가장 빠르고 쉬운 방법입니다.</p>
<p>자바스크립트에서는 별도의 <code>public</code>, <code>private</code>가 없기 때문에 일종의 코딩 컨벤션으로 사용 됐습니다.
그래서 <code>public</code>, <code>private</code> 키워드 없이 필드나 메소드를 식별할 때 유용하게 사용할 수 있었습니다.</p>
<h3 id="es2019">ES2019</h3>
<p>이전의 자바스크립트 클래스에서는 기본적으로 접근지정자 키워드가 존재하지 않았습니다.
그래서 모든 필드와 메소드는 <code>public</code>으로 설정되어 있어서 쉽게 접근할 수 있었습니다.</p>
<p>하지만 <code>ES2019</code>부터 <code>#</code> 기호를 추가해서 클래스 내부에서 <code>private</code>하게 메소드와 필드를 선언할 수 있습니다.
그리고 <code>_</code> 기호를 이용해서 <code>protected</code> 필드를 모방해서 사용합니다.</p>
<h2 id="마무리">마무리</h2>
<p><code>_</code> 식별자를 찾아보면서 <code>ES2019</code> 스펙에 대해서도 공부가 필요하다고 느꼈습니다! 📚</p>
<p><code>Class</code>에 대한 정리를 하려고 했는데 해당 스펙을 기준으로 어떠한 차이점이 있는지 자세하게 보는 것도 좋을 것 같습니다.
본인이 <code>_</code> 식별자를 이용해서 <code>Class</code> 문법을 작성하고 있다면 자바스크립트 스펙을 확인하고 정식 기능을 사용할지에 대한 고민을 해보는 것도 좋을 것 같습니다.</p>
<p>코딩 컨벤션처럼 관용적인 내용보다는 정식으로 지원하는 기능을 사용하는 것이 더 좋을수도 있지 않을까? 라는 생각도 드네요!</p>
<h2 id="출처">출처</h2>
<ul>
<li><p><a href="https://ko.eferrit.com/javascript%EC%9D%98-%EB%8B%AC%EB%9F%AC-%EA%B8%B0%ED%98%B8-%EC%99%80-%EB%B0%91%EC%A4%84-_/">https://ko.eferrit.com/javascript%EC%9D%98-%EB%8B%AC%EB%9F%AC-%EA%B8%B0%ED%98%B8-%EC%99%80-%EB%B0%91%EC%A4%84-_/</a></p>
</li>
<li><p><a href="https://velog.io/@yes3427/JavaScript-Dollar-Sign-and-Underscore">https://velog.io/@yes3427/JavaScript-Dollar-Sign-and-Underscore</a></p>
</li>
<li><p><a href="https://mkonji23.tistory.com/24">https://mkonji23.tistory.com/24</a></p>
</li>
<li><p><a href="https://leftday.tistory.com/70">https://leftday.tistory.com/70</a></p>
</li>
<li><p><a href="https://bamtory29.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-protected%EC%99%80-private-%EB%A9%A4%EB%B2%84">https://bamtory29.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-protected%EC%99%80-private-%EB%A9%A4%EB%B2%84</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[any와 unknown]]></title>
            <link>https://velog.io/@s_sangs/any-unknown</link>
            <guid>https://velog.io/@s_sangs/any-unknown</guid>
            <pubDate>Wed, 26 Apr 2023 23:33:20 GMT</pubDate>
            <description><![CDATA[<p>이전에 타입스크립트 코딩 컨벤션 관련 내용을 작성하면서 궁금한 점이 생겼습니다.</p>
<p><code>any</code> 혹은 <code>unknown</code> 두 타입은 잘 사용하지 않지만, 어떤 타입을 사용하는게 맞는지에 대한 내용을 다루는 컨벤션이 많았습니다.
그 중에서 우아한형제들 기술블로그에서 해당 내용에 대해서 굉장히 자세하게 작성해주신 내용을 공부 겸 정리해보려고 합니다.
덕분에 <code>any</code> vs <code>unknown</code>을 비롯해서 컨벤션과 관련해서 많은 지식들을 배울 수 있어서 좋았습니다. 👍</p>
<p><strong>짧은 결론은 두 타입 모두 사용하지 않는 것이 좋습니다.</strong> 🙅‍♂️</p>
<p><em>하지만 왜 사용하지 않아야 하는지, 어떠한 차이가 있는지는 알고 사용하지 않는 것이 좋을 것 같습니다</em> </p>
<h2 id="any-vs-unknown"><code>any</code> vs <code>unknown</code></h2>
<h3 id="any"><code>any</code></h3>
<ul>
<li><code>tsconfig</code>에서 <code>strict</code>를 <code>true</code>로 설정하거나, <code>noImplicitAny</code>를 <code>true</code>로 설정하면, 각종 변수에 타입을 지정하지 않았을 때 에러가 발생한다.</li>
<li>타입스크립트에서 기본적으로 타입 추론을 하는데, 추론한 근거가 없으면 암시적으로 <code>any</code>로 할당된다.</li>
<li><code>strict</code> 를 지정하지 않으면 계속 <code>any</code>가 쌓이게 될꺼고 <code>anyScript</code>가 될 수 있다.</li>
<li>이러면 자바스크립트를 쓰는 것과 다르지 않아서 권장하지 않는다.</li>
</ul>
<h3 id="unknown"><code>unknown</code></h3>
<ul>
<li><code>unknown</code>도 마찬가지로 어떠한 타입이든 다 올 수 있지만, 이후 동작에 대한 제어가 가능하다.<pre><code class="language-typescript">const sayNumber = (num: number) =&gt; {
console.log(&#39;num: &#39;, num)
}
</code></pre>
</li>
</ul>
<p>const sum = (a: any, b: any): any =&gt; a + b
const three = sum(1, 2)
sayNumber(three)</p>
<p>const minus = (a: any, b: any): unknown =&gt; a - b
const five = minus(7, 2)
sayNumber(five) // &#39;unknown&#39; 형식의 인수는 &#39;number&#39; 형식의 매개 변수에 할당될 수 없습니다.</p>
<pre><code>


### 코드 설명

- `three`의 타입은 `any`
- `five`의 타입은 `unknown`
- `sayNumber` 함수에 `three`를 넣게 되면 3이 출력
- `sayNumber`에 `five`를 넣게 되면 `unknown` 타입은 `number` 타입의 매개변수에 할당할 수 없음



`sayNumber(five)`를 제대로 사용하기 위해서는

- `minus` 함수의 타입을 `number`로 명확하게 지정한다.
- `five`를 `as number`로 타입 단언을 한다.

의 방식을 이용할 수 있습니다.



물론 이렇게 하는 것보다 제네릭을 사용하는게 일반적입니다.
`any`, `unknown` 모두 아무 타입이나 들어갈 수 있지만, `unknown`은 사용하는 쪽에서 처리를 강제해서 안전하게 사용할 수 있게 해줍니다



### `unknown`의 역할

- 해당 타입으로 지정된 값을 사용할 때가 되면 그 타입이 어떤 타입인지 명확히 알아야 사용할 수 있게 막아주는 역할을 합니다.



### `unknown`을 사용해야 하는 상황
- 적은 상황이지만 `unknown`은 예제와 같이 사용할 케이스가 있다.
```typescript
const isNil = (param: unknown): boolean =&gt; param === null || param === undefined</code></pre><p><code>param</code>을 받아서 <code>null</code>인지 <code>undefined</code>인지 확인해서 <code>true/false</code>를 반환하는 함수입니다.</p>
<p>단순히 <code>null</code>인지 <code>undefined</code>인지 체크만 하면 되기 때문에 어떠한 타입이 들어올지 몰라도 됩니다.
이때는 <code>any</code>를 사용할수도 있습니다. 프로젝트 설정에 따라서 <code>any</code>를 아예 사용하지 못하게 하는 경우가 있는데 이러한 경우에 <code>unknown</code> 타입이 적절하다고 생각합니다.</p>
<h3 id="unknown-사용-예시"><code>unknown</code> 사용 예시</h3>
<pre><code class="language-typescript">function prettyPrint(x: unknown): string {
  if (Array.isArray(x)) {
    return &quot;[&quot; + x.map(prettyPrint).join(&quot;, &quot;) + &quot;]&quot;
  }
  if (typeof x === &quot;string&quot;) {
    return `&quot;${x}&quot;`
  }
  if (typeof x === &quot;number&quot;) {
    return String(x)
  } 
  return &quot;etc.&quot;
}</code></pre>
<p><code>x</code>를 <code>any</code>로 했을 경우 <code>map()</code>, <code>join()</code>을 사용할 수 있는데 <code>unknown</code>일 때 <code>x</code>가 배열인 경우에만 <code>map()</code>, <code>join()</code>을 사용할 수 있도록 강제해줍니다.</p>
<h3 id="결론">결론</h3>
<ul>
<li><code>any</code>는 아무때나 쓸 수 있지만, 타입스크립트를 쓰는 의미가 없게 되버릴 수 있다.</li>
<li><code>unknown</code>을 어쩔 수 없이 써야할 상황이 있을 수 있으나, 이를 사용하는 쪽에서 방어처리를 해서 안전하게 사용이 가능하다.</li>
</ul>
<p>누군가는 다른 의견이 있을 수 있습니다.</p>
<p>이러한 내용에 대해서는 100% 정답이 없는 것 같습니다.
<code>enum</code>, 세미콜론(<code>;</code>) 사용, <code>any</code> vs <code>unknown</code> 처럼 다양한 의견이 나올 수 있죠.</p>
<p>자신만의 확실한 의견이 있다면 어떠한 방식이든 문제가 되지는 않는 것 같습니다! 💪</p>
<h2 id="출처">출처</h2>
<ul>
<li><a href="https://techblog.woowahan.com/9804/#toc-2">https://techblog.woowahan.com/9804/#toc-2</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>