<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>오늘도 한줄</title>
    <link>https://recordoftheday.tistory.com/</link>
    <description>Diving into frontend development &amp;mdash; loving the journey so far (๑&amp;bull;̀ㅂ&amp;bull;́)و✧
</description>
    <language>ko</language>
    <pubDate>Thu, 23 Jul 2026 17:44:52 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>코딩하세현</managingEditor>
    <image>
      <title>오늘도 한줄</title>
      <url>https://tistory1.daumcdn.net/tistory/5161452/attach/db69fab267634e30972b0dc8f747f09b</url>
      <link>https://recordoftheday.tistory.com</link>
    </image>
    <item>
      <title>[TypeScript] 제네릭 인터페이스와 타입 별칭</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%A0%9C%EB%84%A4%EB%A6%AD-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%83%80%EC%9E%85-%EB%B3%84%EC%B9%AD</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;제네릭은 함수뿐만 아니라 인터페이스와 타입 별칭에도 동일하게 적용할 수 있다. 이를 통해 구조는 같지만 내부 프로퍼티의 타입만 다른 다양한 객체를 효율적으로 정의할 수 있다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;1. 제네릭 인터페이스 선언 및 사용&lt;/h3&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 이름 뒤에 타입 변수(&amp;lt;K, V&amp;gt; 등)를 선언하여 사용한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQjQI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;interface KeyPair&amp;lt;K, V&amp;gt; {
  key: K;
  value: V;
}

// 명시적 타입 할당 필수
let keyPair: KeyPair&amp;lt;string, number&amp;gt; = {
  key: &quot;key&quot;,
  value: 0,
};

let keyPair2: KeyPair&amp;lt;boolean, string[]&amp;gt; = {
  key: true,
  value: [&quot;1&quot;],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8&quot;&gt;  주의 사항 (명시적 타입 할당)&lt;/b&gt; 제네릭 함수는 전달되는 인수를 통해 타입 변수를 자동으로 추론하지만, &lt;b data-index-in-node=&quot;60&quot; data-path-to-node=&quot;8&quot;&gt;제네릭 인터페이스는 변수의 타입으로 사용할 때 반드시 꺾쇠(&amp;lt; &amp;gt;) 안에 할당할 타입을 명시&lt;/b&gt;해야 한다. 인터페이스만으로는 타입을 추론할 단서(인수)가 없기 때문이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;타입 변수 = 타입 파라미터 = 제네릭 타입 변수 = 제네릭 타입 프로퍼티&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;2. 인덱스 시그니처와 함께 사용하기&lt;/h2&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;제네릭 인터페이스를 인덱스 시그니처와 결합하면, 키(Key)의 타입은 고정하되 값(Value)의 타입은 유연하게 변하는 객체 타입을 쉽게 정의할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQjgI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;interface Map&amp;lt;V&amp;gt; {
  [key: string]: V;
}

let stringMap: Map&amp;lt;string&amp;gt; = {
  name: &quot;홍길동&quot;, // key는 무조건 string, value는 string으로 고정
};

let booleanMap: Map&amp;lt;boolean&amp;gt; = {
  isActive: true, // key는 무조건 string, value는 boolean으로 고정
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;3. 제네릭 타입 별칭&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스와 마찬가지로 type 키워드를 사용하는 타입 별칭에도 제네릭을 적용할 수 있다. 사용법과 제약 사항(명시적 타입 할당 필수)은 제네릭 인터페이스와 완전히 동일하다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQjwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;type Map2&amp;lt;V&amp;gt; = {
  [key: string]: V;
};

let stringMap2: Map2&amp;lt;string&amp;gt; = {
  key: &quot;string&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;4. [실무 활용 예] 불필요한 타입 좁히기(Type Narrowing) 제거&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;유니온 타입(|) 대신 제네릭 인터페이스를 활용하면,&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;함수 내부에서 매번 타입을 좁혀야 하는 번거로움을 없애고 코드를 훨씬 안전하고 간결하게 작성할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;유저 관리 프로그램을 만들어보겠다. 유저 관리는 학생유저, 개발자 유저가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size18&quot;&gt;❌ 개선 전: 유니온 타입 사용 (비효율적인 타입 좁히기)&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;객체의 프로필이 학생인지 개발자인지 확신할 수 없으므로, 특정 로직을 실행하려면 함수 내부에서 항상 조건문(타입 가드)을 사용해야 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQkAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;interface Student { type: &quot;student&quot;; school: string; }
interface Developer { type: &quot;developer&quot;; skill: string; }

interface User {
  name: string;
  profile: Student | Developer; 
}

function goToSchool(user: User) {
  // 런타임에 일일이 타입을 검사하고 좁혀야 함 (불필요한 방어 로직)
  if (user.profile.type !== &quot;student&quot;) {
    console.log(&quot;잘못 오셨습니다.&quot;);
    return;
  }

  // 이제야 school 속성에 접근 가능
  const school = user.profile.school;
  console.log(`${school}로 등교 완료`);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22&quot;&gt;✅&lt;/b&gt;개선 후: 제네릭 인터페이스 적용 (안전하고 간결함)&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;User 인터페이스를 제네릭으로 설계하여, 객체를 생성하는 시점부터 해당 유저가 어떤 프로필 타입을 가졌는지 명확히 정의한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQkQI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;interface Student { type: &quot;student&quot;; school: string; }
interface Developer { type: &quot;developer&quot;; skill: string; }

// 프로필 타입을 타입 변수 T로 유연하게 정의
interface User&amp;lt;T&amp;gt; {
  name: string;
  profile: T;
}

// 매개변수 타입을 User&amp;lt;Student&amp;gt;로 강제하여 학생만 받음
function goToSchool(user: User&amp;lt;Student&amp;gt;) {
  // 별도의 타입 검사 없이 바로 school 속성에 접근 가능
  const school = user.profile.school;
  console.log(`${school}로 등교 완료`);
}

const studentUser: User&amp;lt;Student&amp;gt; = {
  name: &quot;홍길동&quot;,
  profile: {
    type: &quot;student&quot;,
    school: &quot;가톨릭대학교&quot;,
  },
};

const developerUser: User&amp;lt;Developer&amp;gt; = {
  name: &quot;이정한&quot;,
  profile: {
    type: &quot;developer&quot;,
    skill: &quot;TypeScript&quot;,
  },
};

goToSchool(studentUser);    // ✅ 정상 작동
// goToSchool(developerUser); // ❌ 컴파일 에러 발생 (개발자는 등교 시도 자체가 불가능)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 제네릭을 활용하면 타입 좁히기를 위한 불필요한 방어 로직을 제거할 수 있어 유지보수가 매우 편리해진다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;  핵심 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;유니온 타입:&lt;/b&gt; 데이터가 생성된 후 사용하는 시점에 &quot;이게 뭐지?&quot;라고 물어보고 확인해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;제네릭 인터페이스:&lt;/b&gt; 데이터가 생성되는 시점에 타입을 확정하므로, 사용할 때는 추가 확인 없이 안전하게 기능을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;결과적으로 유지보수가 쉬워지고, 런타임 이전에 코드 작성 단계에서 실수를 방지할 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>  TypeScript</category>
      <category>제네릭</category>
      <category>제네릭인터페이스</category>
      <category>제네릭타입별칭</category>
      <category>타입별칭</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/566</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%A0%9C%EB%84%A4%EB%A6%AD-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%83%80%EC%9E%85-%EB%B3%84%EC%B9%AD#entry566comment</comments>
      <pubDate>Tue, 12 May 2026 18:49:13 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] map, forEach 메서드 타입 정의하기</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScriptmap-forEach-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%83%80%EC%9E%85-%EC%A0%95%EC%9D%98%ED%95%98%EA%B8%B0</link>
      <description>&lt;h2 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;1. map 메서드의 제네릭 타입 정의&lt;/h2&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;map 메서드는 원본 배열의 각 요소를 순회하며 콜백 함수를 실행하고, 그 반환값들을 모아 &lt;b data-index-in-node=&quot;51&quot; data-path-to-node=&quot;4&quot;&gt;새로운 배열&lt;/b&gt;로 반환한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;1-1. 단일 타입 변수를 사용한 정의 (문제 발생)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;초기에는 배열의 타입과 콜백 함수의 반환 타입을 모두 동일한 타입 변수 T로 정의할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQeQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 단일 제네릭: 원본 배열과 반환 배열의 타입이 무조건 같아야 함
function map&amp;lt;T&amp;gt;(arr: T[], callback: (item: T) =&amp;gt; T): T[] {
  let result = [];
  for (let i = 0; i &amp;lt; arr.length; i++) {
    result.push(callback(arr[i]));
  }
  return result;
}

const arr = [1, 2, 3];
map(arr, (it) =&amp;gt; it * 2); // ✅ 반환값: number[]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;문제점:&lt;/b&gt; 콜백 함수가 원본과 &lt;b data-index-in-node=&quot;16&quot; data-path-to-node=&quot;8,0,0&quot;&gt;다른 타입&lt;/b&gt;의 값을 반환하려고 하면 타입 에러가 발생한다. (예: number 요소를 string으로 변환 불가)&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQeg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;// ❌ 에러: T가 number로 추론되었으므로, string을 반환할 수 없음
map(arr, (it) =&amp;gt; it.toString()); 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;1-2. 복수 타입 변수를 사용한 정의 (해결)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;map 메서드는 원본 배열의 타입과 반환되는 새 배열의 타입이 다를 수 있어야 한다. 따라서 입력 타입 T와 출력 타입 U, 두 개의 타입 변수를 사용하여 구조를 분리한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9i3lq/dJMcafzPaqP/mCgEnekP2AgJGC4o7U0QM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9i3lq/dJMcafzPaqP/mCgEnekP2AgJGC4o7U0QM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9i3lq/dJMcafzPaqP/mCgEnekP2AgJGC4o7U0QM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9i3lq%2FdJMcafzPaqP%2FmCgEnekP2AgJGC4o7U0QM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQew&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;// 복수 제네릭: 입력 타입(T)과 출력 타입(U)을 분리
function map&amp;lt;T, U&amp;gt;(arr: T[], callback: (item: T) =&amp;gt; U): U[] {
  let result = [];
  for (let i = 0; i &amp;lt; arr.length; i++) {
    result.push(callback(arr[i]));
  }
  return result;
}

const arr = [1, 2, 3];

// ✅ 정상 동작: T는 number, U는 string으로 추론됨
// 반환값: string[] ([&quot;1&quot;, &quot;2&quot;, &quot;3&quot;])
map(arr, (it) =&amp;gt; it.toString()); 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;2. forEach 메서드의 제네릭 타입 정의&lt;/h2&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;forEach 메서스는 배열의 모든 요소를 순회하며 콜백 함수를 한 번씩 실행할 뿐, &lt;b data-index-in-node=&quot;48&quot; data-path-to-node=&quot;15&quot;&gt;새로운 값을 반환하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;map 메서드와 구조가 비슷하지만, 반환값이 없으므로 콜백 함수의 반환 타입을 void로 지정하며 단일 타입 변수 T만으로도 충분히 구현할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;265&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6TLDR/dJMcadu9ETp/X3vLP5AKp7yKyPY9IDtfc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6TLDR/dJMcadu9ETp/X3vLP5AKp7yKyPY9IDtfc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6TLDR/dJMcadu9ETp/X3vLP5AKp7yKyPY9IDtfc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6TLDR%2FdJMcadu9ETp%2FX3vLP5AKp7yKyPY9IDtfc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;631&quot; height=&quot;265&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forEach 함수의 매개변수 탕비이 unknown으로 지정되어 있기에 제네릭을 적용해서 수정할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjPlsbJ-bKUAxUAAAAAHQAAAAAQfA&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;function forEach&amp;lt;T&amp;gt;(arr: T[], callback: (item: T) =&amp;gt; void) {
  for (let i = 0; i &amp;lt; arr.length; i++) {
    callback(arr[i]);
  }
}

const arr2 = [1, 2, 3];

// 순회하며 콘솔 출력만 수행 (반환값 없음)
forEach(arr2, (it) =&amp;gt; console.log(it)); &lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>foreach</category>
      <category>map</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/565</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScriptmap-forEach-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%83%80%EC%9E%85-%EC%A0%95%EC%9D%98%ED%95%98%EA%B8%B0#entry565comment</comments>
      <pubDate>Tue, 12 May 2026 15:06:56 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 제네릭</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%A0%9C%EB%84%A4%EB%A6%AD</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;제네릭(Generic)은 함수, 인터페이스, 타입 별칭, 클래스 등을 다양한 타입과 함께 안전하게 재사용할 수 있도록 만들어주는 문법이다. 입력된 타입에 따라 반환 타입이 동적으로 결정되도록 할 때 주로 사용한다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. 제네릭이 필요한 상황&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;입력된 매개변수를 그대로 반환하는 함수를 만들 때, any나 unknown을 사용하면 타입 안정성이나 효율성 측면에서 문제가 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-path-to-node=&quot;8,0,0,0&quot;&gt;&lt;b&gt;any 타입의 문제 (타입 안정성 상실)&lt;/b&gt;: 함수의 반환값 타입은 return 되는 값을 기준으로 추론된다. 따라서 매개변수가 any 타입일 때 이를 그대로 반환하면, 결괏값 역시 any 타입으로 추론될 수밖에 없다. &lt;u&gt;이로 인해 변수에 숫자가 할당되었음에도 문자열 메서드를 호출하는 등의 실수를 컴파일 단계에서 잡지 못해 런타임 오류로 이어진다.&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwir2d31sbCUAxUAAAAAHQAAAAAQyAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;function func(value: any) { return value; }

let num = func(10); // return 값에 따라 num도 any 타입으로 추론됨
num.toUpperCase();  // ❌ 컴파일은 통과하지만 런타임 에러 발생&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;unknown 타입의 문제 (불필요한 타입 좁히기):&lt;/b&gt; 잘못된 메서드 호출은 막을 수 있지만, 명백하게 숫자가 반환되는 상황에서도 해당 값을 사용하려면 매번 타입 좁히기를 해야 하는 불편함이 생긴다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;function func(value: unknown) { return value; }

let num = func(10); // num은 unknown 타입으로 추론됨
// num.toFixed();   // ❌ 오류 발생

if (typeof num === &quot;number&quot;) {
  num.toFixed();    // ✅ 타입 좁히기 후 사용 가능 (비효율적)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. 제네릭 함수 선언 및 타입 추론&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;제네릭을 사용하면 &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;9&quot;&gt;인수로 전달하는 값의 타입에 따라 반환값의 타입이 유연하게 결정&lt;/b&gt;된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;제네릭이란? 일반적인, 포괄적인 =&amp;gt; 일반적인 함수(종합병원 생각하자  )&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;=&amp;gt; 모든 타입에 사용할 수 있는 함수&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;기본 문법 및 자동 추론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;함수 이름 뒤에 꺾쇠 &amp;lt;T&amp;gt;(타입 변수)를 선언&lt;/b&gt;&lt;/span&gt;하고, 매개변수와 반환값의 타입을 T로 설정한다. 함수를 호출할 때 전달된 인수의 타입에 따라 T가 자동으로 추론된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;타입 변수에 어떤 타입이 담기느냐는 언제 결정되냐?&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;함수를 우리가 호출할때 결정된다.&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwir2d31sbCUAxUAAAAAHQAAAAAQiAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;// 제네릭 함수 선언
function func&amp;lt;T&amp;gt;(value: T): T {
  return value;
}

// 자동 타입 추론
let num = func(10);       // T가 number로 추론됨 -&amp;gt; 반환값도 number
let str = func(&quot;string&quot;); // T가 string으로 추론됨 -&amp;gt; 반환값도 string
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;명시적 타입 할당&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 기본적으로 변수를 더 넓은 범용적인 타입으로 추론한다(예: 튜플을 일반 배열로 추론)&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;개발자가 의도한 명확한 타입이 있다면 함수 호출 시 꺾쇠(&amp;lt; &amp;gt;) 안에 타입을 직접 명시할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbID5U/dJMcabKYwU8/qzU4CplhZsFES8Ouwl4qE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbID5U/dJMcabKYwU8/qzU4CplhZsFES8Ouwl4qE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbID5U/dJMcabKYwU8/qzU4CplhZsFES8Ouwl4qE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbID5U%2FdJMcabKYwU8%2FqzU4CplhZsFES8Ouwl4qE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;520&quot; height=&quot;383&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwir2d31sbCUAxUAAAAAHQAAAAAQiQI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;// T에 [number, number, number] 튜플 타입을 명시적으로 할당
let arr = func&amp;lt;[number, number, number]&amp;gt;([1, 2, 3]);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;함수를 실행할 때 꺾쇠(&amp;lt; &amp;gt;) 안에 원하는 타입을 직접 적어주면 그 타입이 함수 내부의 빈칸을 채우는 확실한 기준이 된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;즉, 함수의 입력값과 결괏값 모두 개발자가 꺾쇠 안에 지정해 준 타입으로 형태가 똑같이 맞춰져서 동작하게 된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;코드 작성 프로그램(IDE)에서 결괏값에 마우스를 올려보면, 컴퓨터가 임의로 넓게 짐작한 타입이 아니라 개발자가 처음부터 의도하고 콕 집어준 정확한 타입으로 잘 적용된 것을 확인할 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size23&quot;&gt;요약: 제네릭(Generic) 함수의 동작 원리&lt;/h3&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4&quot;&gt;제네릭 함수&lt;/b&gt;는 타입 변수를 활용하여 다양한 타입의 값을 인수로 받고 범용적으로 동작할 수 있도록 만든 함수다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;선언:&lt;/b&gt; 함수 이름 뒤에 꺾쇠(&amp;lt; &amp;gt;)를 사용하여 타입 변수(예: &amp;lt;T&amp;gt;)를 선언한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;타입 추론 (자동 결정):&lt;/b&gt; 타입 변수에 할당될 타입은 함수를 호출할 때 전달하는 &lt;b data-index-in-node=&quot;45&quot; data-path-to-node=&quot;5,1,0&quot;&gt;인수(Argument)의 타입&lt;/b&gt;에 따라 자동으로 추론되어 결정된다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,0&quot;&gt;명시적 정의:&lt;/b&gt; 인수를 통한 자동 추론에 의존하지 않고, 함수를 호출할 때 개발자가 꺾쇠 안에 할당될 타입을 직접 명시적으로 정의할 수도 있다. (예: func&amp;lt;number&amp;gt;(10))&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;</description>
      <category>  TypeScript</category>
      <category>명시적타입할당</category>
      <category>제네릭</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/563</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%A0%9C%EB%84%A4%EB%A6%AD#entry563comment</comments>
      <pubDate>Mon, 11 May 2026 17:23:56 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 인터페이스와 클래스</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
      <description>&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트에서 인터페이스는 객체의 형태뿐만 아니라 &lt;b data-index-in-node=&quot;29&quot; data-path-to-node=&quot;8&quot;&gt;클래스의 설계도&lt;/b&gt; 역할도 수행한다. 클래스가 가져야 할 필드와 메서드의 규격을 인터페이스로 먼저 정의하고, 이를 기반으로 클래스를 구현할 수 있다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;implements 키워드 사용&lt;/h2&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;클래스를 선언할 때 implements 키워드와 함께 인터페이스를 지정하면, 해당 클래스는 인터페이스에 정의된 모든 조건을 강제로 만족(구현)해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1778477065435&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 클래스의 설계도(인터페이스) 정의
interface CharacterInterface {
  name: string;
  moveSpeed: number;
  move(): void;
}

// 2. 인터페이스를 구현(implements)하는 클래스
class Character implements CharacterInterface {
  // 필드 정의
  name: string;
  moveSpeed: number;

  constructor(name: string, moveSpeed: number) {
    this.name = name;
    this.moveSpeed = moveSpeed;
  }
  move(): void {
    console.log(`${this.moveSpeed}속도로 이동! `);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제없이 코드가 잘 돌아간다. 여기서 contructor 매개변수의 접근 제어자를 달아주면&lt;/p&gt;
&lt;pre id=&quot;code_1778477132460&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 클래스의 설계도(인터페이스) 정의
interface CharacterInterface {
  name: string;
  moveSpeed: number;
  move(): void;
}

// 2. 단축 문법을 적용하여 구현한 클래스
class Character implements CharacterInterface {
  // 필드 선언과 초기화를 생성자 매개변수(public)로 한 번에 처리
  constructor(public name: string, public moveSpeed: number) {}

  move(): void {
    console.log(`${this.moveSpeed} 속도로 이동!`);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깔끔하게 구현할 수 있다.&amp;nbsp;&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;*인터페이스는 무조건 public 필드만 정의할 수 있다. 만일 private 필드가 필요하면 밑에 코드처럼 따로 정의해줘야한다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwir2d31sbCUAxUAAAAAHQAAAAAQoQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// 1. 클래스의 설계도(인터페이스) 정의
interface CharacterInterface {
  name: string;
  moveSpeed: number;
  move(): void;
}

// 2. 인터페이스를 구현(implements)하는 클래스
class Character implements CharacterInterface {
  constructor(
    public name: string,
    public moveSpeed: number,
    private extra: string // 인터페이스에 없는 필드도 자유롭게 추가 가능
  ) {}

  move(): void {
    console.log(`${this.moveSpeed} 속도로 이동!`);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;규격 강제:&lt;/b&gt; Character 클래스는 CharacterInterface를 구현하므로, name, moveSpeed 필드와 move 메서드를 반드시 포함해야 한다. 누락되거나 타입이 다르면 컴파일 에러가 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;확장성:&lt;/b&gt; 인터페이스에 정의된 필수 요소만 모두 구현한다면, extra처럼 클래스 내부에서 자체적인 필드나 메서드를 추가하는 것은 자유롭다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>  TypeScript</category>
      <category>인터페이스</category>
      <category>인터페이스와클래스</category>
      <category>클래스</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/562</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%81%B4%EB%9E%98%EC%8A%A4#entry562comment</comments>
      <pubDate>Mon, 11 May 2026 14:27:33 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 접근 제어자(Access Modifier)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%A0%91%EA%B7%BC-%EC%A0%9C%EC%96%B4%EC%9E%90Access-Modifier</link>
      <description>&lt;div id=&quot;model-response-message-contentr_176fe59385fd0169&quot;&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;접근 제어자(Access Modifier)는 &lt;u&gt;타입스크립트에서 클래스의 특정 필드나 메서드에 접근할 수 있는 범위를 제한하는 기능이다.&lt;/u&gt; 타입스크립트는 세 가지 접근 제어자를 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;public: 모든 범위에서 접근 가능 (기본값)&lt;/li&gt;
&lt;li&gt;private: 클래스 내부에서만 접근 가능&lt;/li&gt;
&lt;li&gt;protected: 클래스 내부 및 자식 클래스 내부에서만 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;1. public&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;어디서든 접근할 수 있음을 의미한다. 필드나 메서드 선언 시 접근 제어자를 생략하면 기본적으로 public이 적용된다. 명시적으로 작성할 수도 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjW68mlyKuUAxUAAAAAHQAAAAAQeg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;class Employee {
  // 접근 제어자를 생략하면 자동으로 public 적용
  public name: string; 
  age: number; 
  position: string;

  constructor(name: string, age: number, position: string) {
    this.name = name;
    this.age = age;
    this.position = position;
  }
}

const employee = new Employee(&quot;이정환&quot;, 27, &quot;developer&quot;);
// 외부에서 자유롭게 접근 및 수정 가능
employee.name = &quot;홍길동&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;2. private&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;해당 클래스 내부에서만 접근할 수 있다. 클래스 외부나 자식 클래스에서는 접근 및 수정이 불가능하다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;메서드 안에서만 접근하려면 private 설정을 해두면 된다. &lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjW68mlyKuUAxUAAAAAHQAAAAAQew&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;class Employee {
  private name: string; // 클래스 내부에서만 접근 가능
  public age: number;
  public position: string;
  // ... 생략
  
  work() {
    console.log(`${this.name}이 일함`); // ✅ 클래스 내부이므로 접근 가능
  }
}

const employee = new Employee(&quot;이정환&quot;, 27, &quot;developer&quot;);
employee.name = &quot;홍길동&quot;; // ❌ 에러: private 속성이므로 외부 접근 불가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;3. protected&lt;/h3&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;private과 유사하지만, 해당 클래스를 상속받은 &lt;b data-index-in-node=&quot;29&quot; data-path-to-node=&quot;17&quot;&gt;자식 클래스 내부에서의 접근을 허용&lt;/b&gt;한다는 점이 다르다. 외부 접근은 여전히 차단된다.&amp;nbsp;&lt;b&gt;파생클래스까지 허용하고 싶으면 protected 사용하기&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjW68mlyKuUAxUAAAAAHQAAAAAQfA&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Employee {
  private name: string;
  protected age: number; // 자식 클래스까지 접근 허용
  public position: string;
  // ... 생략
}

class ExecutiveOfficer extends Employee {
  func() {
    this.name; // ❌ 에러: private 속성은 자식 클래스에서도 접근 불가
    this.age;  // ✅ 가능: protected 속성이므로 자식 클래스에서 접근 가능
  }
}

const employee = new Employee(&quot;이정환&quot;, 27, &quot;developer&quot;);
employee.age = 30; // ❌ 에러: 클래스 외부이므로 접근 불가
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;[핵심 팁] 생성자 매개변수 프로퍼티 (필드 선언 생략)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트에서는 생성자의 매개변수에 접근 제어자를 직접 설정할 수 있다. 이 기능을 사용하면 코드를 획기적으로 간결하게 만들 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;생성자 매개변수에 접근 제어자(public, private, protected)를 지정하면, 타입스크립트가 다음 두 가지 작업을 자동으로 수행한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;23&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;동일한 이름의 클래스 필드 선언&lt;/li&gt;
&lt;li&gt;생성자 내부에서의 값 할당 (this.필드 = 매개변수)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;따라서 개발자는 &lt;b data-index-in-node=&quot;9&quot; data-path-to-node=&quot;24&quot;&gt;클래스의 필드 선언부와 생성자 내부의 할당 코드를 모두 생략&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjW68mlyKuUAxUAAAAAHQAAAAAQfQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;1057&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blEcBV/dJMcabD9VQk/LwzlwxhvA7EEEr8EkvGmx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blEcBV/dJMcabD9VQk/LwzlwxhvA7EEEr8EkvGmx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blEcBV/dJMcabD9VQk/LwzlwxhvA7EEEr8EkvGmx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblEcBV%2FdJMcabD9VQk%2FLwzlwxhvA7EEEr8EkvGmx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;377&quot; height=&quot;460&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;1057&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 개선 전: 필드 선언과 할당 코드가 중복됨
class Employee {
  private name: string;
  protected age: number;
  public position: string;

  constructor(private name: string, protected age: number, public position: string) {
    this.name = name;
    this.age = age;
    this.position = position;
  }
}

// 개선 후: 타입스크립트의 단축 문법 적용
class Employee {
  // 필드 선언과 값 할당이 자동으로 처리됨
  constructor(
    private name: string,
    protected age: number,
    public position: string
  ) {}

  work() {
    console.log(`${this.name} 일함`);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt; 타입스크립트에서 클래스를 작성할 때는 이 방식을 사용하여 중복 코드를 제거하고 간결하게 작성하는 것을 권장한다.  객체 지향 프로그래밍을 할때 접근 제어자의 역할은 중요해진다. (은닉화를 하기 위해)&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>private</category>
      <category>Protected</category>
      <category>Public</category>
      <category>접근제어자</category>
      <category>타입스립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/561</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%A0%91%EA%B7%BC-%EC%A0%9C%EC%96%B4%EC%9E%90Access-Modifier#entry561comment</comments>
      <pubDate>Mon, 11 May 2026 13:23:37 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입스크립트의 클래스</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
      <description>&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;클래스&lt;/h2&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;클래스부터 만들기 전&amp;nbsp;객체를 먼저 만들면 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체 만들기   클래스 만들기   필드 만들기 in 클래스&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;필드 타입을 정의할 경우&amp;nbsp;&lt;b&gt;암시적으로 'any' 형식&lt;/b&gt;이 포함된다는 오류 메시지가 뜬다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778305505956&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const employee = {
  name: '이정환',
  age: 27,
  position: 'developer',
  worl() {
    console.log('일함');
  },
};

class Employee {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7&quot;&gt;왜?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;타입을 생략하면 암시적 any 타입으로 추론되어 엄격한 타입 검사 모드(strict: true)에서 오류가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;(tsconfig.json에서 &quot;noImplicitAny&quot;에서 false를 작성하면 any타입으로 추론하고 오류 사라진다. &amp;larr; 사용안하는게 좋음)&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot; data-path-to-node=&quot;7&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b data-path-to-node=&quot;7&quot; data-index-in-node=&quot;0&quot;&gt;그래서?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트에서 클래스 필드를 선언할 때는 반드시 타입을 명시해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;생성자에서 필드를 초기화하지 않는다면, 필드 선언과 동시에 이니셜라이저(초기값)을 할당해야 한다. &lt;u&gt;&lt;i data-index-in-node=&quot;48&quot; data-path-to-node=&quot;8&quot;&gt;(반대로 생성자에서 필드 값을 할당하는 경우에는 선언 시 초기값을 생략할 수 있다.)&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj1xb_yvquUAxUAAAAAHQAAAAAQmAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bobFkJ/dJMb99TQQjv/NfHU4oyOQ1pCMPVx1n3q0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bobFkJ/dJMb99TQQjv/NfHU4oyOQ1pCMPVx1n3q0k/img.png&quot; data-alt=&quot;age:number로 수정해야함. 오타임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bobFkJ/dJMb99TQQjv/NfHU4oyOQ1pCMPVx1n3q0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbobFkJ%2FdJMb99TQQjv%2FNfHU4oyOQ1pCMPVx1n3q0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;415&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;415&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;age:number로 수정해야함. 오타임&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오류를 없애는 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 선택적 프로퍼티를 사용 ?:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 기본 값 넣기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 생성자 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;생성자&lt;/b&gt;를 만들어서 오류를 없애준다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778306497224&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const employee = {
  name: '이정환',
  age: 27,
  position: 'developer',
  worl() {
    console.log('일함');
  },
};

class Employee {
  // 필드
  name: string;
  age: number;
  positon: string;

  // 생성자
  constructor(name: string, age: number, position: string) {
    this.name = name;
    this.age = age;
    this.positon = position;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; background-color: #f6e199;&quot;&gt;객체 만들기   클래스 만들기   필드 만들기 in 클래스 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;  생성자 만들기 in 클래스  &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;생성자 만들기 in 클래스  &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 매서드 정의&lt;/span&gt;&amp;nbsp;in 클래스&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1778306636569&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
타입스크립트의 클래스
*/

const employee = {
  name: '이정환',
  age: 27,
  position: 'developer',
  work() {
    console.log('일함');
  },
};

class Employee {
  // 필드
  name: string;
  age: number;
  positon: string;

  // 생성자
  constructor(name: string, age: number, position: string) {
    this.name = name;
    this.age = age;
    this.positon = position;
  }

  // 매서드
  work() {
    console.log('일함');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 다 만듦&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Employee {
  // 생성자에서 초기화하므로 초기값 생략 가능
  name: string;
  age: number;
  
  // 선택적 프로퍼티(Optional Property): 필드명 뒤에 '?' 기호 사용
  position?: string; 

  constructor(name: string, age: number, position: string) {
    this.name = name;
    this.age = age;
    this.position = position;
  }

  work() {
    console.log(&quot;일함&quot;);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10&quot;&gt;클래스 자체를 타입으로 활용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트에서 클래스는 그 자체로 타입으로 사용할 수 있다. &lt;u&gt;클래스 이름을 타입으로 지정하면, 해당 변수는 클래스가 생성하는 인스턴스와 동일한 형태(프로퍼티와 메서드 구조)를 가져야 한다&lt;/u&gt;.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj1xb_yvquUAxUAAAAAHQAAAAAQmQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;// Employee 클래스와 동일한 구조를 요구함
const employeeC: Employee = {
  name: &quot;이정환&quot;,
  age: 27,
  work() {
    console.log(&quot;일함&quot;);
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12&quot;&gt;Employee 같은 클래스는 자바스크립트 클래스로 취급되면서 동시에 타입으로도 취급이 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;즉! 클래스 자체가 하나의 타입으로 작용한다는 것이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;왜?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 구조적 타입을 결정하는&amp;nbsp;&lt;b&gt;구조적 타입 시스템을 따르기 때문&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12&quot;&gt;상속과 super 키워드&lt;/b&gt;&lt;/h2&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;자식 클래스(파생 클래스)에서 새로운 생성자를 정의할 때는 반드시 super()를 호출하여 부모 클래스의 생성자를 실행해야 합니다. 이때 super() 호출은 자식 생성자 내부의 가장 첫 줄(최상단)에 위치해야 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj1xb_yvquUAxUAAAAAHQAAAAAQmgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;class ExecutiveOffice extends Employee {
  // 필드
  officeNumber: number;

  // 생성자
  constructor(
    name: string,
    age: number,
    position: string,
    officeNumber: number,
  ) {
    super(name, age, position); // 부모 생성자 최상단 호출
    this.officeNumber = officeNumber;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;3. [추가 심화 개념] 실무에서 자주 쓰는 TS 클래스 문법&lt;/h2&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;원문 코드의 중복을 획기적으로 줄여주는 타입스크립트만의 강력한 클래스 문법 두 가지를 추가로 소개해보겠음!&lt;/p&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;1. 접근 제어자 (Access Modifiers)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 객체 지향 프로그래밍의 캡슐화를 위해 세 가지 접근 제어자를 지원한다. (자바스크립트의 # 프라이빗 필드와 유사하지만, 컴파일 단계에서 타입을 검사하는 목적이 강하다.)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;public: 기본값. 어디서나 접근 가능&lt;/li&gt;
&lt;li&gt;private: 클래스 내부에서만 접근 가능 (인스턴스 외부에서 접근 불가)&lt;/li&gt;
&lt;li&gt;protected: 클래스 내부 및 해당 클래스를 상속받은 자식 클래스에서만 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size26&quot;&gt;2. 생성자 매개변수 프로퍼티 (Parameter Properties)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;가장 추천하는 문법입니다. 생성자 매개변수 앞에 접근 제어자(public, private, protected)를 붙이면, 번거로운 &lt;b data-index-in-node=&quot;73&quot; data-path-to-node=&quot;21&quot;&gt;필드 선언과 초기화(this.xxx = xxx) 과정을 완벽하게 생략&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22&quot;&gt;기존 방식 (장황함):&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj1xb_yvquUAxUAAAAAHQAAAAAQmwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;class Employee {
  public name: string;
  private age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24&quot;&gt;단축 방식 (권장):&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj1xb_yvquUAxUAAAAAHQAAAAAQnAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;class Employee {
  // 필드 선언과 초기화를 한 번에 처리
  constructor(public name: string, private age: number) {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 작성해도 타입스크립트가 알아서 클래스 필드를 만들고 값을 할당해 주므로 코드가 매우 간결해진다.&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>상속</category>
      <category>클래스</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/560</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%81%B4%EB%9E%98%EC%8A%A4#entry560comment</comments>
      <pubDate>Sat, 9 May 2026 15:19:07 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] 자바스크립트의 클래스</title>
      <link>https://recordoftheday.tistory.com/entry/JavaScript-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
      <description>&lt;div id=&quot;model-response-message-contentr_e4be8a234a8332fd&quot;&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;클래스&lt;/h2&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;동일한 구조와 동작을 가진 객체를 더 쉽고 효율적으로 생성하기 위한 템플릿(틀) 문법이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;객체 리터럴({...}) 방식을 사용해 동일한 형태의 객체(예: 학생 정보)를 여러 개 생성하면 코드가 중복된다. 100명, 1,000명의 데이터를 다루어야 한다면 유지보수가 매우 어려워지며, 클래스는 이러한 중복을 제거하고 코드를 구조화하는 데 도움을 준다. 흔히 클래스를 '붕어빵 틀'에, 클래스로부터 생성된 실체 객체를 '붕어빵(&lt;b data-index-in-node=&quot;187&quot; data-path-to-node=&quot;5&quot;&gt;인스턴스, Instance&lt;/b&gt;)'에 비유한다.&lt;/p&gt;
&lt;pre id=&quot;code_1778225350132&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let studentA = {
  name: '이정환',
  grade: 'A+',
  age: 27,
  student() {
    console.log('열심히 공부함');
  },
  introduce() {
    console.log('안녕하세요');
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. 클래스와 필드 선언&lt;/h2&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;클래스는&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt; class 키워드를 사용&lt;/span&gt;하여 선언한다. &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;클래스 내부에는 생성될 객체가 가질 속성인 필드를 정의&lt;/span&gt;할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi03-rsj6mUAxUAAAAAHQAAAAAQ4QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Student {
  // 필드 선언 (인스턴스가 가질 프로퍼티)
  name;
  age;
  grade;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;*&lt;/span&gt;클래스의 이름은&amp;nbsp;&lt;b&gt;앞글자를 대문자로&lt;/b&gt;하는 파스칼 케이스를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;field(필드)&lt;/span&gt;란?&amp;nbsp;&lt;b&gt;클래스가 만들어낼 객체 프로퍼티&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;class 키워드 사용해 클래스 선언 &amp;rarr; 클래스 내부 필드 선언&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;2. 생성자와 인스턴스 생성&lt;/h2&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;생성자&lt;/b&gt;는 새로운 객체를 만들어라고 호출하면 실제 객체를 생성하는 역할을 하는 함수 =&amp;gt; 객체를 만드는 메서드&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi03-rsj6mUAxUAAAAAHQAAAAAQ4gE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Student {
  name;
  age;
  grade;

  // 생성자: 객체를 초기화하는 역할
  constructor(name, grade, age) {
    this.name = name;
    this.grade = grade;
    this.age = age;
  }
}

// 인스턴스 생성
const studentB = new Student(&quot;홍길동&quot;, &quot;A+&quot;, 27);
console.log(studentB); 
// 출력: Student { name: '홍길동', age: 27, grade: 'A+' }
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;new 키워드:&lt;/b&gt; &lt;u&gt;클래스를 호출하여 새로운 객체(인스턴스)&lt;/u&gt;를 생성할 때 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;this 키워드:&lt;/b&gt; 클래스 내부에서 this는 &lt;b data-index-in-node=&quot;25&quot; data-path-to-node=&quot;12,1,0&quot;&gt;새롭게 생성될 현재 인스턴스&lt;/b&gt;를 가리킨다. 즉, this.name = name은 새로 만들어지는 객체의 name 프로퍼티에 매개변수로 받은 값을 할당하라는 의미다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;class 키워드 사용해 클래스 선언&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 클래스 내부 필드 선언&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 생성자 만들기&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;span&gt;&amp;nbsp;=&amp;gt; 클래스를 호출해서 객체를 생성할때는 new 키워드 사용하기&lt;/span&gt;&lt;/u&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;3. 메서드 정의&lt;/h2&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;클래스 내부에 함수를 선언하여 객체가 수행할 동작(메서드)을 정의할 수 있다. 메서드 내부에서도 this를 활용해 객체 자신의 데이터에 접근할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi03-rsj6mUAxUAAAAAHQAAAAAQ4wE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Student {
  // ... (필드 및 생성자 생략)

  study() {
    console.log(&quot;열심히 공부 함&quot;);
  }

  introduce() {
    console.log(`안녕하세요! ${this.name}입니다.`); // this로 필드에 접근
  }
}

let studentB = new Student(&quot;홍길동&quot;, &quot;A+&quot;, 27);
studentB.study();      // 출력: 열심히 공부 함
studentB.introduce();  // 출력: 안녕하세요! 홍길동입니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size26&quot;&gt;4. 상속 과 super&lt;/h2&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;extends 키워드를 사용하면 기존 클래스의 필드와 메서드를 그대로 물려받는(상속하는) 새로운 클래스를 만들 수 있다. 이를 통해 기존 코드를 재사용하면서 기능을 확장할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;자식 클래스에서 새로운 생성자를 정의할 때는 반드시 &lt;b data-index-in-node=&quot;29&quot; data-path-to-node=&quot;18&quot;&gt;super()&lt;/b&gt; 메서드를 호출해야 한다. &lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;super()는 부모 클래스의 생성자를 실행하여 상속받은 필드들을 정상적으로 초기화하는 역할을 한다.&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi03-rsj6mUAxUAAAAAHQAAAAAQ5AE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;// Student 클래스를 상속받는 StudentDeveloper 클래스
class StudentDeveloper extends Student {
  favoriteSkill; // 추가된 필드

  constructor(name, grade, age, favoriteSkill) {
    // 1. 부모 클래스(Student)의 생성자 호출
    super(name, grade, age); 
    // 2. 자식 클래스만의 필드 초기화
    this.favoriteSkill = favoriteSkill;
  }

  programming() {
    console.log(`${this.favoriteSkill}(으)로 프로그래밍 함`);
  }
}

let devStudent = new StudentDeveloper(&quot;이정환&quot;, &quot;A&quot;, 27, &quot;JavaScript&quot;);
devStudent.introduce();   // 부모의 메서드 사용 가능
devStudent.programming(); // 자식의 메서드 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size26&quot;&gt;  [추가 심화 개념] 모던 자바스크립트 클래스 기능&lt;/h2&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 클래스를 다룰 때 반드시 알아야 하는 추가 기능들이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;5. 정적 프로퍼티와 메서드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;static 키워드를 붙이면 개별 인스턴스가 아닌 &lt;b data-index-in-node=&quot;28&quot; data-path-to-node=&quot;24&quot;&gt;클래스 자체에 속하는&lt;/b&gt; 데이터나 동작을 정의할 수 있다. 인스턴스를 생성(new)하지 않아도 클래스 이름으로 직접 호출할 수 있어, 유틸리티 함수를 만들 때 주로 사용한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi03-rsj6mUAxUAAAAAHQAAAAAQ5QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Student {
  static studentCount = 0; // 정적 필드

  constructor(name) {
    this.name = name;
    Student.studentCount++; // 인스턴스가 생성될 때마다 증가
  }

  static printCount() {    // 정적 메서드
    console.log(`총 학생 수: ${Student.studentCount}`);
  }
}

new Student(&quot;홍길동&quot;);
new Student(&quot;이정환&quot;);
Student.printCount(); // 출력: 총 학생 수: 2 (인스턴스 없이 클래스명으로 바로 호출)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;6. 비공개(Private) 필드와 Getter / Setter&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;클래스 외부에서 특정 데이터를 마음대로 수정하지 못하게 보호하려면 필드명 앞에 #을 붙여 비공개(Private) 필드로 만든다. 이 값에 접근하거나 수정하려면 get과 set 키워드를 사용한 접근자 메서드를 활용한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi03-rsj6mUAxUAAAAAHQAAAAAQ5gE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Student {
  #age; // 외부에서 접근 불가능한 비공개 필드

  constructor(name, age) {
    this.name = name;
    this.#age = age;
  }

  // 값을 읽을 때 사용 (Getter)
  get age() {
    return this.#age;
  }

  // 값을 수정할 때 사용 (Setter) - 안전한 값인지 검증 가능
  set age(value) {
    if (value &amp;lt; 0) {
      console.log(&quot;나이는 0보다 작을 수 없습니다.&quot;);
      return;
    }
    this.#age = value;
  }
}

const student = new Student(&quot;홍길동&quot;, 20);
// console.log(student.#age); // ❌ 에러 발생 (직접 접근 불가)
console.log(student.age);     // ✅ 20 (Getter 호출)

student.age = -5;             // ✅ Setter 호출 (검증 로직 실행: 나이는 0보다 작을 수 없습니다.)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>  JavaScript/JavaScript</category>
      <category>자바스크립트</category>
      <category>클래스</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/559</guid>
      <comments>https://recordoftheday.tistory.com/entry/JavaScript-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%81%B4%EB%9E%98%EC%8A%A4#entry559comment</comments>
      <pubDate>Fri, 8 May 2026 17:09:42 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 선언 병합</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%84%A0%EC%96%B8-%EB%B3%91%ED%95%A9</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입 별칭(type)은 동일한 스코프 내에서 중복 선언이 불가능하지만, &lt;u&gt;&lt;b data-index-in-node=&quot;40&quot; data-path-to-node=&quot;3&quot;&gt;인터페이스는 동일한 이름으로 여러 번 선언할 수 있으며, 이들은 자동으로 하나로 합쳐진다.&lt;/b&gt;&lt;/u&gt; 이를 &lt;b data-index-in-node=&quot;105&quot; data-path-to-node=&quot;3&quot;&gt;선언 병합&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 기본 동작&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;동일한 이름으로 선언된 여러 인터페이스의 프로퍼티들은 최종적으로 하나의 객체 타입으로 병합된다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwisueS__KiUAxUAAAAAHQAAAAAQggI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 타입 별칭은 중복 선언 불가
type User = { name: string; };
type User = { age: number; }; // ❌ 에러 발생

// 인터페이스는 중복 선언 시 자동 병합됨
interface Person { name: string; }
interface Person { age: number; }

// 병합된 결과: { name: string; age: number; }
const person: Person = {
  name: &quot;이정환&quot;,
  age: 27,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;2. 주의사항: 프로퍼티 타입 충돌&lt;/h2&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;병합되는 인터페이스들 간에 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;8&quot;&gt;동일한 이름의 프로퍼티가 서로 다른 타입을 가질 경우 충돌이 발생&lt;/b&gt;하여 컴파일 에러를 낸다. 선언 병합 시 프로퍼티의 타입은 반드시 일치해야 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwisueS__KiUAxUAAAAAHQAAAAAQgwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;interface Person { 
  name: string; 
}

interface Person {
  name: number; // ❌ 에러: 앞서 정의된 string 타입과 충돌함
  age: number;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언 병합은 모듈 병합일때 주로 활용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 모듈 병합&lt;/h2&gt;
&lt;pre id=&quot;code_1778222567552&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 모듈 보강
interface Lib {
  a: number;
  b: number;
}

const lib: Lib = {
  a: 1,
  b: 2,
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lib에 c를 추가하고 싶을때&amp;nbsp;&lt;b&gt;선언 합침&lt;/b&gt;을 사용하면 좋다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778222614599&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Lib {
  a: number;
  b: number;
}

interface Lib {
  c: string;
}

const lib: Lib = {
  a: 1,
  b: 2,
  c: 'hello',
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>모듈병합</category>
      <category>인터페이스</category>
      <category>인터페이스합침</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/558</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%84%A0%EC%96%B8-%EB%B3%91%ED%95%A9#entry558comment</comments>
      <pubDate>Fri, 8 May 2026 15:44:24 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 인터페이스 확장</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%99%95%EC%9E%A5</link>
      <description>&lt;h3 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size23&quot;&gt;인터페이스 확장이란&lt;/h3&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;extends 키워드를 사용하여 기존 인터페이스의 프로퍼티를 다른 인터페이스가 상속받는 문법이다. 이를 통해 중복 코드를 제거하고 유지보수성을 크게 높일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778220863643&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Animal {
  name: string;
  age: number;
}

interface Dog {
  name: string;
  age: number;
  isBark: boolean;
}

interface Cat {
  name: string;
  age: number;
  isScratch: boolean;
}

interface Chicken {
  name: string;
  age: number;
  isFly: boolean;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;☝  현재 중복된 인터페이스가 많음&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 기본 문법과 필요성&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;공통된 프로퍼티(name, age 등)를 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;부모 인터페이스(Animal)에 정의&lt;/span&gt;하고, &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;파생되는 인터페이스(Dog, Cat)가 이를 확장하도록 구성&lt;/span&gt;한다. 이렇게 하면 &lt;u&gt;부모 인터페이스만 수정해도 상속받은 모든 타입에 변경 사항이 일괄 적용된다&lt;/u&gt;.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwisueS__KiUAxUAAAAAHQAAAAAQ4wE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;interface Animal {
  name: string;
  color: string;
}

// Animal의 모든 프로퍼티(name, color)를 물려받고, isBark를 추가함
interface Dog extends Animal {
  isBark: boolean;
}

const dog: Dog = {
  name: &quot;돌돌이&quot;,
  color: &quot;brown&quot;,
  isBark: true,
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;이때 확장 대상인 Animal은 Dog의 슈퍼타입이 된다. 그러면 cat, chicken도 dog와 같이 작성하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK0Qbj/dJMcagSYZdq/ZfiS4Uip8sZAWOoxjtfyJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK0Qbj/dJMcagSYZdq/ZfiS4Uip8sZAWOoxjtfyJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK0Qbj/dJMcagSYZdq/ZfiS4Uip8sZAWOoxjtfyJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK0Qbj%2FdJMcagSYZdq%2FZfiS4Uip8sZAWOoxjtfyJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;284&quot; height=&quot;234&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. 프로퍼티 재정의&amp;nbsp;&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;상속받는 자식 인터페이스에서 부모의 프로퍼티 타입을 다시 정의할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;주의사항 (서브타입 규칙):&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;background-color: #ef5369; color: #ffffff;&quot;&gt; 재정의할 타입은 반드시 &lt;b data-index-in-node=&quot;29&quot; data-path-to-node=&quot;10,0,0&quot;&gt;원본 타입의 서브타입&lt;/b&gt;이어야 한다. &lt;/span&gt;확장의 본질은 '부모 타입으로도 취급될 수 있어야 함'을 의미하기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwisueS__KiUAxUAAAAAHQAAAAAQ5AE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;interface Animal {
  name: string;
  color: string;
}

interface Dog extends Animal {
  // ✅ 가능: &quot;doldol&quot;(리터럴)은 string의 서브타입이다.
  name: &quot;doldol&quot;; 
  isBark: true;
}

interface Cat extends Animal {
  // ❌ 에러: number는 string의 서브타입이 아니다. 상속 관계가 깨진다.
  name: number; 
  isScratch: boolean;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;3. 타입 별칭 확장&lt;/h2&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스는 다른 인터페이스뿐만 아니라, 객체 형태로 정의된 타입 별칭도 extends로 확장할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwisueS__KiUAxUAAAAAHQAAAAAQ5QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type Animal = {
  name: string;
  color: string;
};

// 객체 형태의 타입 별칭을 상속받음
interface Dog extends Animal {
  isBark: Boolean;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;4. 다중 확장&lt;/h2&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;콤마(,)를 사용하여 두 개 이상의 인터페이스를 동시에 확장할 수 있다. 이를 통해 여러 특성을 조합한 새로운 타입을 쉽게 만들 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwisueS__KiUAxUAAAAAHQAAAAAQ5gE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;interface DogCat extends Dog, Cat {}

const dogCat: DogCat = {
  name: &quot;개냥이&quot;,
  color: &quot;mix&quot;,
  isBark: false,
  isScratch: true, // Cat에서 상속
  // Dog에서 상속받은 프로퍼티도 포함됨
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>다중확장</category>
      <category>인터페이스</category>
      <category>인터페이스확장</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/557</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%99%95%EC%9E%A5#entry557comment</comments>
      <pubDate>Fri, 8 May 2026 15:32:00 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 인터페이스</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4&quot;&gt;인터페이스(상호간에 약속된 규칙)&lt;/b&gt;는 객체의 구조를 정의하고 이름을 붙이는 문법이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;타입 별칭(type)과 유사하게 동작하지만, &lt;u&gt;&lt;b data-index-in-node=&quot;59&quot; data-path-to-node=&quot;4&quot;&gt;객체의 형태를 정의&lt;/b&gt;하는 데 특화되어 있다.&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YFltK/dJMcaf7zH1Y/8gvY9k10fhEZjYn3CFIUHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YFltK/dJMcaf7zH1Y/8gvY9k10fhEZjYn3CFIUHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YFltK/dJMcaf7zH1Y/8gvY9k10fhEZjYn3CFIUHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYFltK%2FdJMcaf7zH1Y%2F8gvY9k10fhEZjYn3CFIUHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;569&quot; height=&quot;320&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. 기본 문법 및 프로퍼티 설정&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;객체가 가져야 할 속성과 타입을 정의한다. 선택적 프로퍼티와 읽기 전용 프로퍼티 설정 방식은 타입 별칭과 동일하다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwisueS__KiUAxUAAAAAHQAAAAAQfw&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;interface Person {
  readonly name: string; // 읽기 전용 (수정 불가)
  age?: number;          // 선택적 프로퍼티 (생략 가능)
}

const person: Person = {
  name: &quot;이정환&quot;,
  // age는 생략 가능
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. 메서드 타입 정의와 오버로딩&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스 내부에서 메서드를 정의하는 방법은 두 가지가 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;오버로딩을 구현하려면 반드시 &lt;b data-index-in-node=&quot;64&quot; data-path-to-node=&quot;9&quot;&gt;호출 시그니쳐&lt;/b&gt; 방식을 사용해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;함수 타입 표현식:&lt;/b&gt; sayHi: () =&amp;gt; void (오버로딩 &lt;b data-index-in-node=&quot;35&quot; data-path-to-node=&quot;10,0,0&quot;&gt;불가능&lt;/b&gt;)&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;호출 시그니쳐:&lt;/b&gt; sayHi(): void (오버로딩 &lt;b data-index-in-node=&quot;29&quot; data-path-to-node=&quot;10,1,0&quot;&gt;가능&lt;/b&gt;)&lt;/u&gt; =&amp;gt; 함수타입이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwisueS__KiUAxUAAAAAHQAAAAAQgAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;interface Person {
  // 호출 시그니쳐를 사용해야 오버로딩이 가능하다.
  sayHi(): void;
  sayHi(a: number): void;
  sayHi(a: number, b: number): void;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;3. 인터페이스와 유니온/인터섹셕 결합&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 말했다싶이&amp;nbsp;&lt;b&gt;인터페이스는 오직 '객체의 구조'를 정의하는 역할&lt;/b&gt;만 한다. 따라서&amp;nbsp;&lt;b&gt;선언부에 직접 유니온이나 인터섹션을 결합하면 문법 에러가 생긴다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1778219971307&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌ 에러: 인터페이스 선언 자체에 유니온을 결합할 수 없음
interface Person {
  name: string;
  sayHi(): void;
} | number;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 인터페이스로 만든 타입(Person)을 다른 타입(numberm string 등)과 묶어서 사용하려면, 제시한 코드처럼&amp;nbsp;&lt;b&gt;외부에서 결합해주어한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 타입 별칭 활용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;type 키워드를 사용하여 유니온이나 인터섹션으로 묶은 새로운 타입을 정의한다. (재사용할 때 유용함)&lt;/p&gt;
&lt;pre id=&quot;code_1778220037396&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Type1 = number | string | Person;
type Type2 = number &amp;amp; string &amp;amp; Person;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 타입 주석에 직접 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수를 선언할 때, 콜론(:) 뒤의 타입 지정 자리에 직접 유니온 타입을 작성한다. (일회성으로 사용할 때 유용함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;span style=&quot;background-color: #f6e199;&quot;&gt;인터페이스는 자체적으로 복잡한 조합(|, &amp;amp;)을 만들지 못하므로, &lt;b data-index-in-node=&quot;44&quot; data-path-to-node=&quot;12&quot;&gt;type 별칭을 빌리거나 변수 선언 시점에 직접 명시하여 조합해야 한다&lt;/b&gt;는 의미다. &lt;/span&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;4. 헝가리안 표기법&lt;/h2&gt;
&lt;pre id=&quot;code_1778220153391&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IPerson {
  readonly name: string;
  age?: number;
  sayHi(): void; // 메서드의 이름이 소괄호 앞에 붙는다.
  sayHi(): void;
  sayHi(a: number, b: number): void;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Person앞에 I를 붙이는것이다. 타입스크립트 공식 가이드라인과 최신 실무에서는 인터페이스에 I를 붙이는 것을 지양한다고 구글링에서 찾았다.&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>메서드오버로딩</category>
      <category>인터페이스</category>
      <category>타입별칭</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/556</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4#entry556comment</comments>
      <pubDate>Fri, 8 May 2026 15:09:30 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 함수 오버로딩</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%95%A8%EC%88%98-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;함수 오버로딩은 하나의 함수가 &lt;b data-index-in-node=&quot;17&quot; data-path-to-node=&quot;3&quot;&gt;매개변수의 개수나 타입에 따라 여러가지 버전으로 만드는&lt;/b&gt;&amp;nbsp;문법이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트에서 이를 구현하려면 &lt;b data-index-in-node=&quot;73&quot; data-path-to-node=&quot;3&quot;&gt;오버로드 시그니쳐&lt;/b&gt;와 &lt;b data-index-in-node=&quot;84&quot; data-path-to-node=&quot;3&quot;&gt;구현 시그니쳐&lt;/b&gt;를 각각 작성해야 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 오버로드 시그니쳐 (Overload Signature)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;함수의 &lt;b data-index-in-node=&quot;4&quot; data-path-to-node=&quot;5&quot;&gt;선언부&lt;/b&gt;만 작성하여, 이 함수가 어떤 매개변수 조합으로 호출될 수 있는지 정의한다. 구현부({})는 포함하지 않는다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;버전1: 매개변수 1개   이 매개변수에 20을 곱한 값 출력&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;버전2: 매개변수 2개   이 매개변수들을 다 더한 값을 출력&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj-l--UiYaSAxUAAAAAHQAAAAAQpQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// 버전 1: 매개변수 1개
function func(a: number): void;
// 버전 2: 매개변수 3개
function func(a: number, b: number, c: number): void;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;위 코드는 func 함수가 &quot;매개변수 1개&quot; 또는 &quot;매개변수 3개&quot;를 받는 두 가지 버전으로만 호출될 수 있음을 명시한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. 구현 시그니쳐 (Implementation Signature)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;실제로 함수가 실행되는 &lt;b data-index-in-node=&quot;13&quot; data-path-to-node=&quot;9&quot;&gt;구현부&lt;/b&gt;를 정의한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;호환성 규칙:&lt;/b&gt; 구현 시그니쳐의 매개변수 타입은 &lt;b data-index-in-node=&quot;26&quot; data-path-to-node=&quot;10,0,0&quot;&gt;정의된 모든 오버로드 시그니쳐를 포괄&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;작성 요령:&lt;/b&gt; 위 예시의 경우, 매개변수 1개짜리 호출에도 대응해야 하므로 b와 c를 &lt;b&gt;선택적 매개변수(?)&lt;/b&gt;로 정의해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj-l--UiYaSAxUAAAAAHQAAAAAQpgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;// 실제 구현부
function func(a: number, b?: number, c?: number) {
  if (typeof b === &quot;number&quot; &amp;amp;&amp;amp; typeof c === &quot;number&quot;) {
    console.log(a + b + c); // 버전 2 로직
  } else {
    console.log(a * 20);    // 버전 1 로직
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;3. 호출 및 주의사항&lt;/h2&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;함수를 호출할 때는 &lt;b data-index-in-node=&quot;11&quot; data-path-to-node=&quot;13&quot;&gt;오버로드 시그니쳐&lt;/b&gt;에 정의된 형태만 유효하다. 구현 시그니쳐가 더 넓은 범위를 허용하더라도, 오버로드 시그니쳐에 없는 형태는 에러로 처리된다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj-l--UiYaSAxUAAAAAHQAAAAAQpwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func(1);        // ✅ 버전 1 (성공)
func(1, 2, 3);  // ✅ 버전 2 (성공)
func(1, 2);     // ❌ 에러: 매개변수 2개짜리 오버로드 시그니쳐는 존재하지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>  TypeScript</category>
      <category>구현</category>
      <category>구현시그니처</category>
      <category>시그너치</category>
      <category>오버로드</category>
      <category>오버로드시그니처</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/550</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%95%A8%EC%88%98-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9#entry550comment</comments>
      <pubDate>Mon, 12 Jan 2026 23:34:22 +0900</pubDate>
    </item>
    <item>
      <title>[타입스크립트] 타입의 호환성</title>
      <link>https://recordoftheday.tistory.com/entry/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%9D%98-%ED%98%B8%ED%99%98%EC%84%B1</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;함수 타입의 호환성이란, &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;4&quot;&gt;특정 함수 타입을 다른 함수 타입으로 취급해도 안전한지(할당 가능한지)를 판단하는 기준&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;두 가지 요소에 의해 결정&lt;/u&gt;된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;5&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;반환값(Return Type)&lt;/b&gt;이 호환되는가? 공변성 (Covariance)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;매개변수(Parameter)&lt;/b&gt;이 호환되는가? &amp;nbsp;반공변성 (Contravariance)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. 기준: 반환값 타입 (공변성)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;반환값은&lt;b&gt; '출력(Output)'&lt;/b&gt;이다. 할당받는 쪽(Target)이 기대하는 타입보다 할당되는 쪽(Source)의 타입이 더 구체적(서브타입)이거나 같으면 호환된다. &lt;u&gt;반환값끼리 업캐스팅이 된거는 호환된다.&lt;/u&gt; 이를 &lt;b data-index-in-node=&quot;99&quot; data-path-to-node=&quot;7&quot;&gt;공변성&lt;/b&gt;이라 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;규칙:&lt;/b&gt; Target &amp;supe; Source (반환값 타입이 더 넓거나 같아야 함)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;예시:&lt;/b&gt; number를 기대하는 변수에 10( 넘버 리터럴)을 반환하는 함수를 넣는 것(다운 캐스팅)은 안전하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwj-l--UiYaSAxUAAAAAHQAAAAAQaA&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type A = () =&amp;gt; number; // 넓은 타입 (Super)
type B = () =&amp;gt; 10;     // 좁은 타입 (Sub)

let a: A = () =&amp;gt; 10; // 반환값: number
let b: B = () =&amp;gt; 10; // 반환값: number 리터럴

a = b; // ✅ 가능: number 타입 공간에 10을 담을 수 있음(cuz 업캐스팅)
b = a; // ❌ 불가능: 10만 들어갈 공간에 모든 number를 담을 수 없음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU7YeD/dJMcagYvTAh/8NcsKBZbF5UGlFc7aKvft1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU7YeD/dJMcagYvTAh/8NcsKBZbF5UGlFc7aKvft1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU7YeD/dJMcagYvTAh/8NcsKBZbF5UGlFc7aKvft1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU7YeD%2FdJMcagYvTAh%2F8NcsKBZbF5UGlFc7aKvft1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;207&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;2. 기준: 매개변수 타입 (반공변성) - &lt;b data-index-in-node=&quot;24&quot; data-path-to-node=&quot;10&quot;&gt;핵심&lt;/b&gt;&lt;/h2&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;매개변수는 &lt;b&gt;'입력(Input)'&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;반환값과 달리, 할당받는 쪽(Target)의 매개변수 타입보다 할당되는 쪽(Source)의 매개변수 타입이 더 넓거나(슈퍼타입) 같아야 호환된다. 이를 &lt;b data-index-in-node=&quot;110&quot; data-path-to-node=&quot;11&quot;&gt;반공변성&lt;/b&gt;이라 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;이 부분이 직관과 반대되어 헷갈리기 쉽다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt; &lt;b&gt;&quot;함수는 자신이 처리할 수 있는 입력의 범위가 넓을수록, 좁은 범위를 다루는 곳에 대타로 뛸 수 있다&lt;/b&gt;&quot;&lt;/u&gt;고 이해하면 된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13&quot;&gt;2-1. 매개변수의 개수가 같을 때&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768224732399&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type C = (value: number) =&amp;gt; void; // 매개변수가 상위 타입 (Number)
type D = (value: 10) =&amp;gt; void;     // 매개변수가 하위 타입 (Number Literal)

let c: C = (value) =&amp;gt; {};
let d: D = (value) =&amp;gt; {};

// 상황 1: C 타입 변수에 D 타입 함수 할당 (❌ 불가능)
// c는 아무 숫자나 넣어서 호출할 수 있는데, d는 10만 처리할 수 있다.
// 매개변수 관점에서는 상위 타입으로의 할당(업캐스팅)처럼 보이지만, 함수에서는 이것이 '불안전'하다.
c = d; 

// 상황 2: D 타입 변수에 C 타입 함수 할당 (✅ 가능)
// d는 10만 넣어서 호출한다. c는 모든 숫자를 처리할 수 있으므로 10도 당연히 처리한다.
// 매개변수 관점에서는 하위 타입으로의 할당(다운캐스팅)처럼 보이지만, 함수에서는 이것이 '안전'하다.
d = c;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CeHS0/dJMcacaK8KC/vkjeFxASjUBNY4I2oNdES1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CeHS0/dJMcacaK8KC/vkjeFxASjUBNY4I2oNdES1/img.png&quot; style=&quot;width: 45.3409%; margin-right: 10px;&quot; width=&quot;314&quot; height=&quot;291&quot; data-widthpercent=&quot;45.87&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-origin-height=&quot;508&quot; data-origin-width=&quot;549&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CeHS0/dJMcacaK8KC/vkjeFxASjUBNY4I2oNdES1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCeHS0%2FdJMcacaK8KC%2FvkjeFxASjUBNY4I2oNdES1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;549&quot; height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZBhfY/dJMcabpnuIa/GfaWS1GivFKPQFwL1vYg4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZBhfY/dJMcabpnuIa/GfaWS1GivFKPQFwL1vYg4k/img.png&quot; style=&quot;width: 53.4963%;&quot; width=&quot;357&quot; height=&quot;280&quot; data-widthpercent=&quot;54.13&quot; data-filename=&quot;blob&quot; data-is-animation=&quot;false&quot; data-origin-height=&quot;538&quot; data-origin-width=&quot;686&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZBhfY/dJMcabpnuIa/GfaWS1GivFKPQFwL1vYg4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZBhfY%2FdJMcabpnuIa%2FGfaWS1GivFKPQFwL1vYg4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;686&quot; height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;규칙:&lt;/b&gt; Target &amp;sube; Source (매개변수 타입이 더 좁거나 같아야 함)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;예시:&lt;/b&gt; Dog(서브) 타입을 다루는 자리에 Animal(슈퍼) 타입을 다루는 함수가 올 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwj-l--UiYaSAxUAAAAAHQAAAAAQaQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;type Animal = { name: string };
type Dog = { name: string; color: string }; // Dog는 Animal의 서브타입

let animalFunc = (animal: Animal) =&amp;gt; { console.log(animal.name); };
let dogFunc = (dog: Dog) =&amp;gt; { console.log(dog.name, dog.color); };

// 상황 1: dogFunc 자리에 animalFunc 할당 (✅ 가능)
// dogFunc는 Dog 객체(name, color)를 받는다.
// animalFunc는 Animal 객체(name)만 있으면 작동한다.
// Dog는 name을 가지고 있으므로 animalFunc가 처리하는 데 문제 없다.
dogFunc = animalFunc; 

// 상황 2: animalFunc 자리에 dogFunc 할당 (❌ 불가능)
// animalFunc는 Animal 객체(name만 있음)를 받는다.
// dogFunc는 Dog 객체(color도 필요함)를 기대한다.
// Animal에는 color가 없으므로 dogFunc가 에러를 낼 수 있다.
animalFunc = dogFunc;
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;1021&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TMagj/dJMcaajIc3Y/r6ktm7YKnsk6DGuIO1I6S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TMagj/dJMcaajIc3Y/r6ktm7YKnsk6DGuIO1I6S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TMagj/dJMcaajIc3Y/r6ktm7YKnsk6DGuIO1I6S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTMagj%2FdJMcaajIc3Y%2Fr6ktm7YKnsk6DGuIO1I6S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;269&quot; height=&quot;293&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;1021&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16&quot;&gt;2-2. 매개변수의 개수가 다를 때&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;규칙:&lt;/b&gt; 할당되는 쪽(Source)의 매개변수 개수가 더 적어야 한다. (타입이 호환된다는 전제하에)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;이유:&lt;/b&gt; 자바스크립트/타입스크립트에서는 함수에 정의된 것보다 더 많은 인자를 넘겨도 무시될 뿐 에러가 나지 않는다. 반대로 필요한 인자가 부족하면 문제가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwj-l--UiYaSAxUAAAAAHQAAAAAQag&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;type Func1 = (a: number, b: number) =&amp;gt; void; // 2개 필요
type Func2 = (a: number) =&amp;gt; void;            // 1개 필요

let func1: Func1 = (a, b) =&amp;gt; {};
let func2: Func2 = (a) =&amp;gt; {};

func1 = func2; // ✅ 가능: func1은 인자 2개를 주지만, func2는 1개만 받고 나머지 무시함 (안전)
func2 = func1; // ❌ 불가능: func2는 인자 1개를 주는데, func1은 2개를 요구함 (불안전)
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHeYQI/dJMcachwB1m/bKKZiM5Vkdgeo0R2Nn05O1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHeYQI/dJMcachwB1m/bKKZiM5Vkdgeo0R2Nn05O1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHeYQI/dJMcachwB1m/bKKZiM5Vkdgeo0R2Nn05O1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHeYQI%2FdJMcachwB1m%2FbKKZiM5Vkdgeo0R2Nn05O1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;383&quot; height=&quot;290&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size26&quot;&gt;[정리]&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,0,0&quot;&gt;반환값(Output):&lt;/b&gt; &lt;b data-index-in-node=&quot;13&quot; data-path-to-node=&quot;21,0,0&quot;&gt;다운캐스팅&lt;/b&gt;처럼 동작 (넓은 그릇에 작은 물건 담기 OK) &amp;rarr; &lt;b data-index-in-node=&quot;47&quot; data-path-to-node=&quot;21,0,0&quot;&gt;공변성&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,1,0&quot;&gt;매개변수(Input):&lt;/b&gt; &lt;b data-index-in-node=&quot;13&quot; data-path-to-node=&quot;21,1,0&quot;&gt;업캐스팅&lt;/b&gt;처럼 동작 (까다로운 조건(Dog) 자리에 너그러운 조건(Animal) 함수 쓰기 OK) &amp;rarr; &lt;b data-index-in-node=&quot;69&quot; data-path-to-node=&quot;21,1,0&quot;&gt;반공변성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>  TypeScript</category>
      <category>공변성</category>
      <category>반공병성</category>
      <category>타입스크립트</category>
      <category>타입의호환성</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/549</guid>
      <comments>https://recordoftheday.tistory.com/entry/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%83%80%EC%9E%85%EC%9D%98-%ED%98%B8%ED%99%98%EC%84%B1#entry549comment</comments>
      <pubDate>Mon, 12 Jan 2026 23:29:34 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 단일 연결 리스트 (Push, Pop)</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%8B%A8%EC%9D%BC-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8-Push-Pop</link>
      <description>&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. 연결 리스트(Linked List)란 무엇인가?&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;연결 리스트는 문자열, 숫자 등 원하는 데이터를 저장하는 자료 구조다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;배열(Array)처럼 순서에 따라 다수의 데이터를 저장하지만, 구조적으로 큰 차이가 있다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;배열(Array) vs 연결 리스트(Linked List)&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 68px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;배열&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;연결 리스트&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;순서대로&amp;nbsp;&lt;b&gt;인덱스&lt;/b&gt;가 부여된다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;인덱스&lt;b&gt;가 없다.&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;삽입과 삭제가 오래 걸릴 수 있다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;next&amp;nbsp;&lt;/b&gt;포인터를 가진 노드들을 통해 연결된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;특정 인덱스에&amp;nbsp;&lt;b&gt;빠르게 접근&lt;/b&gt;할 수 있다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;임의 접근이 허용되지 않는다&lt;br /&gt;(예를 들어: &quot;열 번째&quot; 항목이 필요할 경우 바로 그 값을 얻을 수 없다.)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;2. 연결 리스트의 구조와 용어&lt;/h2&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;  연결 리스트는 마치 객차들이 연속으로 연결된 &lt;b data-index-in-node=&quot;25&quot; data-path-to-node=&quot;10&quot;&gt;기차&lt;/b&gt;와 같다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;노드(Node):&lt;/b&gt; 리스트를 구성하는 각 요소를 말한다. 각 노드는&lt;b&gt; '데이터(값)'&lt;/b&gt;와 '&lt;b&gt;다음 노드를 가리키는 정보(Next Pointer)'&lt;/b&gt;를 저장한다.&lt;u&gt; 더 이상 다음 노드가 없을 경우 null을 저장한다.&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;헤드(Head):&lt;/b&gt; 연결 리스트의 &lt;b data-index-in-node=&quot;18&quot; data-path-to-node=&quot;11,1,0&quot;&gt;시작 노드&lt;/b&gt;를 가리킨다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,0&quot;&gt;테일(Tail):&lt;/b&gt; 연결 리스트의 &lt;b data-index-in-node=&quot;18&quot; data-path-to-node=&quot;11,2,0&quot;&gt;마지막 노드&lt;/b&gt;를 가리킨다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,3,0&quot;&gt;길이(Length):&lt;/b&gt; 리스트의 길이를 추적 및 유지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;중간에 있는 노드들은 일일이 추적하지 않는다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;오직 '헤드'가 어디 있는지만 알고 있으며, 헤드에서 시작해 다음, 그 다음 노드로 이동하며 마지막까지 접근하는 방식이다.&lt;/u&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;3. 접근 방식의 차이 (비유)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uvNZz/dJMcaiosjbP/E8VzJvKkOOrLLkCnlOAzq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uvNZz/dJMcaiosjbP/E8VzJvKkOOrLLkCnlOAzq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uvNZz/dJMcaiosjbP/E8VzJvKkOOrLLkCnlOAzq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuvNZz%2FdJMcaiosjbP%2FE8VzJvKkOOrLLkCnlOAzq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;587&quot; height=&quot;292&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;연결 리스트는 인덱스가 없기 때문에 &quot;10번째 데이터를 달라&quot;고 바로 요청할 수 없다(임의 접근 불가)&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;반드시 첫 번째 노드부터 시작해서 순서대로 따라가야 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;이를 &lt;b&gt;'엘리베이터가 있는 건물'&lt;/b&gt;과 &lt;b&gt;'없는 건물'&lt;/b&gt;로 비유할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;배열&lt;/span&gt; (엘리베이터 O):&lt;/b&gt; &quot;5층으로 가줘&quot;라고 하면 바로 5층으로 갈 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;연결 리스트&lt;/span&gt; (엘리베이터 X):&lt;/b&gt; 각 층을 연결하는 계단만 있다. 5층에 가려면 1층부터 계단을 따라 순서대로 올라가야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-path-to-node=&quot;17&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;17,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0&quot;&gt;참고:&lt;/b&gt; '단방향(Singly)'이라는 용어는 각 노드가 다음 노드로 오직 &lt;b data-index-in-node=&quot;41&quot; data-path-to-node=&quot;17,0&quot;&gt;한 방향&lt;/b&gt;으로만 연결되었다는 뜻이다. &lt;br /&gt;(양방향은 역방향 연결도 가지고 있다.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size26&quot;&gt;4. 왜 연결 리스트를 사용하는가?&lt;/h2&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;배열이 있는데 굳이 연결 리스트를 배워야 하는 이유는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b data-index-in-node=&quot;30&quot; data-path-to-node=&quot;19&quot;&gt;데이터의 삽입(Insertion)과 제거(Removal)&lt;/b&gt; &lt;/span&gt;때문이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;배열&lt;/span&gt;의 단점:&lt;/b&gt; 인덱스를 가지고 있기 때문에, 맨 앞이나 중간에 데이터를 추가하면 그 뒤의 모든 항목의 인덱스를 다시 매겨야 하는 &lt;b&gt;물결 효과(Ripple Effect)&lt;/b&gt;가 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;연결 리스트&lt;/span&gt;의 장점:&lt;/b&gt; 인덱스가 없으므로 재정렬할 필요가 없다. 새로운 노드를 추가할 때, 헤드가 새 노드를 가리키게 하고 새 노드가 기존 노드를 가리키게 하는 식으로 &lt;b data-index-in-node=&quot;93&quot; data-path-to-node=&quot;20,1,0&quot;&gt;연결 고리(포인터)만 바꿔주면 된다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &lt;u&gt;임의 접근(Random Access)이 필요 없고, 대용량 데이터의 &lt;b data-index-in-node=&quot;42&quot; data-path-to-node=&quot;21&quot;&gt;삽입과 삭제가 빈번한 경우&lt;/b&gt; 연결 리스트가 배열보다 유리하다.&lt;/u&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size26&quot;&gt;1. 기본 구조 만들기: Node와 SinglyLinkedList 클래스&lt;/h2&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;연결 리스트를 구현하기 위해서는 두 가지 클래스가 필요하다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;3&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,0,0&quot;&gt;Node:&lt;/b&gt; 데이터를 저장하고 다음 노드를 가리키는 기본 단위.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,1,0&quot;&gt;SinglyLinkedList:&lt;/b&gt; 노드들을 관리하고 조작(추가, 삭제 등)하는 메인 클래스.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1-1. Node 클래스 정의&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;노드는 매우 단순하다.&lt;b&gt; 값(val)&lt;/b&gt;과 다음 노드에 대한 &lt;b&gt;참조(next)&lt;/b&gt;만 있으면 된다. =&amp;gt; 단순 객차&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj-sLyL9_ORAxUAAAAAHQAAAAAQyAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;class Node {
    constructor(val) {
        this.val = val;      // 데이터 저장
        this.next = null;    // 다음 노드를 가리킴 (초기값은 null)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node가 알아야 할 일:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내 값(val)은 뭐지?&lt;/li&gt;
&lt;li&gt;다음 노드는 어디(next)?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기값을 null로 작성한 이유는&amp;nbsp;&lt;b&gt;리스트가 비어있음&lt;/b&gt;을 나타내기 위해서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 추가시 좋지 않은 방법 &amp;rarr; 반복 수행해야함으로 번거로움&lt;/p&gt;
&lt;pre id=&quot;code_1767608795023&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 좋지 않은 방법
let first = new Node(&quot;Hi&quot;)
first.next = new Node(&quot;there&quot;)
first.next.next = new Node(&quot;how&quot;)
first.next.next.next = new Node(&quot;are&quot;)
first.next.next.next.next = new Node(&quot;you&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;15&quot;&gt;push 메서드 코드&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;GromitWallaceAndGromitGIF.gif&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9X95i/dJMcabQqyrM/3s5bKvMWAszkCrhlKXMSy0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9X95i/dJMcabQqyrM/3s5bKvMWAszkCrhlKXMSy0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9X95i/dJMcabQqyrM/3s5bKvMWAszkCrhlKXMSy0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/9X95i/dJMcabQqyrM/3s5bKvMWAszkCrhlKXMSy0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;315&quot; data-filename=&quot;GromitWallaceAndGromitGIF.gif&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깔끔하게 보이기 위해 &lt;b&gt;SinglyLinkedList&lt;/b&gt; &lt;b&gt;클래스&lt;/b&gt;를 만든다. (SinglyLinkedList는 전체 리스트 관리(기차 전체 관리자))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SinglyLinkedList가 알아야할 일:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;맨 처음(head)는 어디?&lt;/li&gt;
&lt;li&gt;맨 끝(tail)은 어디?&lt;/li&gt;
&lt;li&gt;총 몇 개인지(length)?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서의 constructor에서는 어떤 데이터로도 초기화 시킬 필요가 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1767609083663&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SinglyLinkedList{
	constructor() {
    }
}

let list = new SinglyLinkedList()
list.push(&quot;Hello&quot;)
list.push(&quot;GoodBye&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;연결 리스트의 시작점인 head, 끝점인 tail, 그리고 리스트의 크기인 length를 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj-sLyL9_ORAxUAAAAAHQAAAAAQyQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767613424441&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SinglyLinkedList {
    constructor() {
        this.head = null;    // 리스트의 시작
        this.tail = null;    // 리스트의 끝
        this.length = 0;     // 리스트의 길이
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트의 맨 끝에 새로운 노드를 추가하는 push 메서드를 구현해 보겠다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 push와 같은 역할을 하지만, 연결 리스트에서는 인덱스 대신 &lt;b&gt;포인터(next, tail)&lt;/b&gt;를 조정해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767613531873&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Node{
    constructor(val){
        this.val = val;
        this.next = null;
    }
}

class SinglyLinkedList{
// 매개변수가 비어있는 이유는 push를 하기 위해서
    constructor(){
        this.head = null;
        this.tail = null;
        this.length = 0;
    }
    push(val){
    	// new Node(val) 한번 만 만든이유: 변수에 저장하였기 때문에 재사용이 가능하다.
        let newNode = new Node(val);
        if(!this.head){
            this.head = newNode; // 맨앞=맨뒤=첫 객차
            this.tail = this.head; // 첫 객차: head==tail
        } else {
            this.tail.next = newNode;  // 마지막 객차 다음=새 객차(현재 꼬리 객차의 &quot;다음 자리&quot;에 새 객차 연결)
            this.tail = newNode;    // 새 객차=새로운 마지막(리스트의 새 꼬리를 새 객차로 업데이트)
        }
        this.length++;
        return this;
    }
}

var list = new SinglyLinkedList()
list.push(&quot;HELLO&quot;)
list.push(&quot;GOODBYE&quot;)
console.log(list);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KlGC8/dJMcabbPcTs/KxDTMjY4zj2kWVPr4LEAQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KlGC8/dJMcabbPcTs/KxDTMjY4zj2kWVPr4LEAQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KlGC8/dJMcabbPcTs/KxDTMjY4zj2kWVPr4LEAQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKlGC8%2FdJMcabbPcTs%2FKxDTMjY4zj2kWVPr4LEAQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;613&quot; height=&quot;89&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;89&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tail.next = newNode &amp;rarr; tail = newNode 순서&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQoF5N/dJMcaiotFqJ/eHclyfwZuTlaF673tYzEU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQoF5N/dJMcaiotFqJ/eHclyfwZuTlaF673tYzEU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQoF5N/dJMcaiotFqJ/eHclyfwZuTlaF673tYzEU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQoF5N%2FdJMcaiotFqJ%2FeHclyfwZuTlaF673tYzEU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;290&quot; height=&quot;413&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;pop() 메서드&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;BalloonRedGIF.gif&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WYJoI/dJMcaiPvOWa/Arqi8pyUQZs6W0VFuffIg1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WYJoI/dJMcaiPvOWa/Arqi8pyUQZs6W0VFuffIg1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WYJoI/dJMcaiPvOWa/Arqi8pyUQZs6W0VFuffIg1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/WYJoI/dJMcaiPvOWa/Arqi8pyUQZs6W0VFuffIg1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;262&quot; data-filename=&quot;BalloonRedGIF.gif&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3&quot;&gt;pop() 메서드&lt;/b&gt;는 연결 리스트의 가장 마지막 노드를 제거하고 그 값을 반환하는 기능이다.&lt;/p&gt;
&lt;pre id=&quot;code_1767876596725&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Node{
    constructor(val){
        this.val = val;
        this.next = null;
    }
}

class SinglyLinkedList{
    constructor(){
        this.head = null;
        this.tail = null;
        this.length = 0;
    }
    push(val){
        var newNode = new Node(val);
        if(!this.head){
            this.head = newNode;
            this.tail = this.head;
        } else {
            this.tail.next = newNode;
            this.tail = newNode;
        }
        this.length++;
        return this;
    }
    pop(){
        if(!this.head) return undefined; //  빈 기차 = 제거할 객차 없음!
        var current = this.head; // current: 기차 앞부터
        var newTail = current;    // newTail: 새 꼬리 후보
        while(current.next){    // 다음 객차 있는 동안
            newTail = current; // newTail: 현재 객차로 갱신
            current = current.next;  // current: 다음 객차로 이동
        } //  제거된 객차 = current (while 탈출 후)
        this.tail = newTail; //새 꼬리 지정 + 연결 끊기
        this.tail.next = null;
        this.length--;
        if(this.length === 0){
            this.head = null; // 빈 리스트면 head/tail 둘 다 null
            this.tail = null;
        }
        return current;

    }
}


var list = new SinglyLinkedList()
list.push(&quot;HELLO&quot;) 
list.push(&quot;GOODBYE&quot;)
list.push(&quot;!&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sc0KV/dJMcaiBYvfW/Nfp9JFciXKyNLbQrov6EJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sc0KV/dJMcaiBYvfW/Nfp9JFciXKyNLbQrov6EJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sc0KV/dJMcaiBYvfW/Nfp9JFciXKyNLbQrov6EJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsc0KV%2FdJMcaiBYvfW%2FNfp9JFciXKyNLbQrov6EJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;643&quot; height=&quot;814&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;814&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;왜 undefined가 아닌 null?&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #4d4d4c; text-align: right;&quot;&gt;&lt;span&gt;✅ null = &quot;포인터가 가리킬 게 없음&quot; (객차 연결) &lt;/span&gt;&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #4d4d4c; text-align: right;&quot;&gt;✅ undefined = &quot;함수가 아무것도 반환 안 함&quot; (함수 결과)&lt;/span&gt; &lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  알고리즘&amp;amp;자료구조</category>
      <category>POP</category>
      <category>push</category>
      <category>연결리스트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/548</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%8B%A8%EC%9D%BC-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8-Push-Pop#entry548comment</comments>
      <pubDate>Thu, 8 Jan 2026 21:51:41 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 함수 타입 표현식과 호출 시그니쳐</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%95%A8%EC%88%98-%ED%83%80%EC%9E%85-%ED%91%9C%ED%98%84%EC%8B%9D%EA%B3%BC-%ED%98%B8%EC%B6%9C-%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B3%90</link>
      <description>&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 함수 타입 표현식 (Function Type Expression)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;타입 별칭을 사용하여 화살표 함수 문법으로 타입을 정의하는 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,0&quot;&gt;특징:&lt;/b&gt; 함수 선언과 타입 선언을 분리할 수 있어 코드가 간결해진다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;활용:&lt;/b&gt; 사칙연산 함수들처럼 매개변수와 반환값의 구조가 동일한 경우, 하나의 타입으로 일괄 적용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQugI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// 타입 별칭으로 정의
type Operation = (a: number, b: number) =&amp;gt; number;

// 동일한 타입을 여러 함수에 재사용
const add: Operation = (a, b) =&amp;gt; a + b;
const sub: Operation = (a, b) =&amp;gt; a - b;
// 이렇게도 사용가능
const multipy: (a: number, b: number) =&amp;gt; number = (a, b) =&amp;gt; a * b;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. 호출 시그니쳐 (Call Signature)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 함수가 객체라는 점에 착안하여, 객체 리터럴 형태로 함수의 타입을 정의하는 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;구문:&lt;/b&gt; 중괄호 { } 안에 (매개변수): 반환타입 형식으로 작성한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;하이브리드 타입:&lt;/b&gt; 호출 시그니쳐와 함께 일반 프로퍼티를 추가하면, &lt;b&gt;'함수이자 동시에 객체'&lt;/b&gt;인 타입을 정의할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQuwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 호출 시그니쳐 정의
type Operation2 = {
  (a: number, b: number): number; // 함수로서의 호출 구조
  name: string;                   // 객체로서의 속성 (하이브리드 타입)
};

const add2: Operation2 = (a, b) =&amp;gt; a + b;
add2.name = &quot;AddFunction&quot;;

add2(1, 2); // 함수로 호출 가능
console.log(add2.name); // 객체 속성 접근 가능&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>  TypeScript</category>
      <category>콜시그니처</category>
      <category>타입스크립트</category>
      <category>표현식</category>
      <category>함수타입표현식</category>
      <category>호출시크니처</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/547</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%95%A8%EC%88%98-%ED%83%80%EC%9E%85-%ED%91%9C%ED%98%84%EC%8B%9D%EA%B3%BC-%ED%98%B8%EC%B6%9C-%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B3%90#entry547comment</comments>
      <pubDate>Thu, 8 Jan 2026 21:03:01 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 함수 타입</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%95%A8%EC%88%98-%ED%83%80%EC%9E%85</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;함수의 타입은 &lt;b data-index-in-node=&quot;8&quot; data-path-to-node=&quot;3&quot;&gt;매개변수&lt;/b&gt;와 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;3&quot;&gt;반환값&lt;/b&gt;의 타입으로 결정된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;함수를 설명하는 가장 좋은 방법&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[자바스크립트 ver] 어떤 매개변수를 받고, 어떠 떤 결과값을 받는지 얘기한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;[타입스크립트 ver] 어떤 [타입의] 매개변수를 받고 어떤 [타입의] 결과값을 반환하는지 얘기한다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 기본 타입 정의&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 함수 선언 방식에 매개변수와 반환값의 타입을 추가하여 정의한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;화살표 함수 또한 동일한 방식으로 정의한다. &lt;b&gt;단, 반환값의 타입은 타입스크립트가 자동으로 추론하므로 생략할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQpgI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 함수 선언식
function func(a: number, b: number): number {
  return a + b;
}

// 화살표 함수 (반환 타입 생략 가능)
const add = (a: number, b: number) =&amp;gt; a + b;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;2. 매개변수 기본값 (Default Parameters)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;매개변수에 기본값을 설정하면(name = &quot;이정환&quot;), 타입스크립트가 해당 값의 타입을 자동으로 추론한다. 따라서 &lt;u&gt;별도의 타입 정의를 생략할 수 있다.&lt;/u&gt; &lt;b&gt;이때 추론된 타입과 다른 타입의 값을 인수로 전달하거나, 명시적으로 다른 타입을 정의하면 오류가 발생한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767869994969&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function introduce(name = '이정환', tall: number) {
  console.log(`name:${name}`);
  console.log(`tall:${tall}`);
}

introduce('이정환', 175);

// ❌ 틀린 방법
function introduce(name: number = '이정환') {
  console.log(`name:${name}`);
}

// ❌ 틀린 방법
introduce(1);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;3. 선택적 매개변수 (Optional Parameters)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;매개변수명 뒤에 ?를 붙여 생략 가능한 선택적 매개변수로 지정할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;타입 추론:&lt;/b&gt; 해당 매개변수는 Type | undefined 유니온 타입으로 추론된다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;주의 사항:&lt;/b&gt; 값을 안전하게 사용하려면 &lt;b data-index-in-node=&quot;21&quot; data-path-to-node=&quot;11,1,0&quot;&gt;타입 좁히기&lt;/b&gt;가 필요하며, 선택적 매개변수는 반드시 &lt;b data-index-in-node=&quot;49&quot; data-path-to-node=&quot;11,1,0&quot;&gt;필수 매개변수 뒤&lt;/b&gt;에 위치해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQpwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;function introduce(name = '이정환', age: number, tall?: number) {
  console.log(`name:${name}`);

  if (typeof tall === 'number') {
    console.log(`tall:${tall + 10}`); // 타입 좁히기 후 사용
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;4. 나머지 매개변수 (Rest Parameters)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;여러 개의 인수를 배열 형태로 받는 ...rest 파라미터는 &lt;b data-index-in-node=&quot;34&quot; data-path-to-node=&quot;14&quot;&gt;배열 타입&lt;/b&gt;으로 정의한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;만약 인수의 개수와 타입을 엄격하게 제한하고 싶다면 &lt;b data-index-in-node=&quot;77&quot; data-path-to-node=&quot;14&quot;&gt;튜플(Tuple)&lt;/b&gt; 타입을 사용할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQqAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// 일반적인 배열 타입
function getSum(...rest: number[]) { ... }

// 개수가 고정된 튜플 타입
function getSumFixed(...rest: [number, number, number]) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>타입스크립트</category>
      <category>함수타입</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/546</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%95%A8%EC%88%98-%ED%83%80%EC%9E%85#entry546comment</comments>
      <pubDate>Thu, 8 Jan 2026 20:09:08 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 서로소 유니온 타입</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%84%9C%EB%A1%9C%EC%86%8C-%EC%9C%A0%EB%8B%88%EC%98%A8-%ED%83%80%EC%9E%85</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4&quot;&gt;서로소 유니온 타입&lt;/b&gt;은 교집합이 없는 타입들&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt; 서로소 관계에 있는 타입들을 모아 만든 유니온 타입을 말한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(두 타입 간에 공통적으로 포함된 값이 하나도 없는 타입, &lt;/b&gt;교집합이 하나도 없는것을 서로소 관계라고 한다.&lt;b&gt;)&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이를 활용하면 &lt;b&gt;타입 가드(Type Guard)&lt;/b&gt;를 훨씬 직관적으로 구현할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2BLNe/dJMcafFiJDY/IOWVK44aUoP8mAmaxzAdH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2BLNe/dJMcafFiJDY/IOWVK44aUoP8mAmaxzAdH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2BLNe/dJMcafFiJDY/IOWVK44aUoP8mAmaxzAdH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2BLNe%2FdJMcafFiJDY%2FIOWVK44aUoP8mAmaxzAdH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;637&quot; height=&quot;246&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. 문제 상황: 직관적이지 않은 타입 분기&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;역할별로 프로퍼티가 다른 3개의 타입(Admin, Member, Guest)이 있고, 이를 하나로 묶은 User 타입이 있다고 가정하자&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQmgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;type Admin = { name: string; kickCount: number; };
type Member = { name: string; point: number; };
type Guest = { name: string; visitCount: number; };

type User = Admin | Member | Guest;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;기존 방식에서는 in 연산자를 사용해 특정 프로퍼티의 존재 여부로 타입을 좁혔다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQmwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;function login(user: User) {
  if (&quot;kickCount&quot; in user) {
    // Admin 타입으로 추론
    console.log(`${user.name}님 현재까지 ${user.kickCount}명 추방했습니다`);
  } else if (&quot;point&quot; in user) {
    // Member 타입으로 추론
    console.log(`${user.name}님 현재까지 ${user.point}모았습니다`);
  } else {
    // Guest 타입으로 추론
    console.log(`${user.name}님 현재까지 ${user.visitCount}번 오셨습니다`);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;이 방식은 코드가 복잡해질수록 조건식만 보고 어떤 타입인지 파악하기 어렵다는 단점이 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size26&quot;&gt;2. 해결 방안: 태그(Tag) 프로퍼티 추가&lt;/h2&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;각 타입에 공통된 프로퍼티(예: tag)를 추가하고, 서로 다른 &lt;b data-index-in-node=&quot;36&quot; data-path-to-node=&quot;12&quot;&gt;문자열 리터럴(String Literal)&lt;/b&gt; 타입을 할당하여 구분한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQnAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;type Admin = { tag: &quot;ADMIN&quot;; name: string; kickCount: number; };
type Member = { tag: &quot;MEMBER&quot;; name: string; point: number; };
type Guest = { tag: &quot;GUEST&quot;; name: string; visitCount: number; };

type User = Admin | Member | Guest;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;3. 개선된 코드: 직관적인 타입 가드 with switch&lt;/h2&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;이제 tag 프로퍼티를 비교하여 타입을 명확하게 분리할 수 있다. switch 문을 사용하면 가독성이 더욱 좋아진다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi77qLTvfuRAxUAAAAAHQAAAAAQnQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function login(user: User) {
  switch (user.tag) {
    case &quot;ADMIN&quot;:
      console.log(`${user.name}님 현재까지 ${user.kickCount}명 추방했습니다`);
      break;
    case &quot;MEMBER&quot;:
      console.log(`${user.name}님 현재까지 ${user.point}모았습니다`);
      break;
    case &quot;GUEST&quot;:
      console.log(`${user.name}님 현재까지 ${user.visitCount}번 오셨습니다`);
      break;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;u&gt;서로소 유니온 타입을 사용하면 컴파일러가 타입을 정확히 추론할 수 있어 코드의 안정성과 가독성이 모두 향상된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;4. 핵심 포인트 &amp;amp; 주의사항&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5&quot;&gt;1) 왜 '서로소(Disjoint)'라고 부르는가?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순히 string 타입으로 정의하면 모든 문자열이 가능하므로 교집합이 생길 수 있다.&lt;/li&gt;
&lt;li&gt;하지만 &quot;ADMIN&quot;, &quot;MEMBER&quot;처럼 &lt;b&gt;리터럴 타입(구체적인 값)&lt;/b&gt;을 사용하면, 두 값은 절대 같을 수 없으므로 &lt;b data-index-in-node=&quot;68&quot; data-path-to-node=&quot;6,1,0&quot;&gt;교집합이 아예 없는(서로소) 상태&lt;/b&gt;가 된다. 이 덕분에 컴퓨터가 타입을 100% 확신하고 분류할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7&quot;&gt;2) 유지보수 측면의 장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 나중에 Manager라는 새로운 타입을 User 유니온에 추가했다고 가정하자.&lt;/li&gt;
&lt;li&gt;tag를 활용한 switch 문을 사용하고 있다면, &lt;b data-index-in-node=&quot;29&quot; data-path-to-node=&quot;8,1,0&quot;&gt;새로운 케이스(Manager)를 처리하지 않았을 때 컴파일러가 경고를 줄 수 있어&lt;/b&gt; 실수를 방지하기 좋다. (타입 안정성 보장)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;복습: 비동기 작업의 결과를 처리하는 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 작업의 결과를 처리하는 객체를 만들어야 된다는 상황을 가정해보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API를 호출한다든지, 서버에서 데이터를 받아온다든지하는 작업을 &lt;b&gt;비동기 작업&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 작업 결과를 처리하는 코드를 작성하다 보면 LOADING, FAILED, SUCCESS와 같은 상태에 따라 완전히 다른 데이터 구조를 다뤄야하는 상황이 발생된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 단순히&amp;nbsp;&lt;b&gt;옵셔널 체이닝(?)&lt;/b&gt;속성을 사용하는 방식은&amp;nbsp;&lt;b&gt;타입의 안정성을 떨어뜨리고, 실제로 존재해야할 값이 없는 상태를 허용하게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이를 해결하기 위해&amp;nbsp;&lt;b&gt;서로소 유니언 타입&lt;/b&gt;을 사용하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 방식의 문제점&lt;/h3&gt;
&lt;pre id=&quot;code_1767867708502&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type AsyncTask = {
state: 'LOADING' | 'FAILED' | 'SUCCESS';
error?: {
message: string;
};
response?: {
data: string;
};
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;FAILED&lt;/span&gt;&lt;span&gt; 상태인데도 &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;가 없을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;SUCCESS&lt;/span&gt;&lt;span&gt; 상태인데도 &lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;가 없을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;TypeScript는 이를 모두 &lt;/span&gt;&lt;b&gt;&lt;span&gt;가능한 상태&lt;/span&gt;&lt;/b&gt;&lt;span&gt;로 인식한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;그 결과 &lt;/span&gt;&lt;span&gt;task.error.message&lt;/span&gt;&lt;span&gt; 같은 접근은 허용되지 않고, 옵셔널 체이닝(&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;)이 강제된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, &lt;/span&gt;&lt;b&gt;&lt;span&gt;논리적으로는 말이 안 되는 상태를 타입이 막아주지 못하는 구조&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비동기 작업 예제로 만든 서로소 유니언 타입&lt;/h3&gt;
&lt;pre id=&quot;code_1767867783903&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type LoadingTask = {
state: 'LOADING';
};


type FailedTask = {
state: 'FAILED';
error: {
message: string;
};
};


type SuccessTask = {
state: 'SUCCESS';
response: {
data: string;
};
};


type AsyncTask = LoadingTask | FailedTask | SuccessTask;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;가 판별자 역할을 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;FAILED&lt;/span&gt;&lt;span&gt; 상태에서는 반드시 &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;가 존재한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;SUCCESS&lt;/span&gt;&lt;span&gt; 상태에서는 반드시 &lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;가 존재한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;잘못된 조합은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;컴파일 단계에서 차단된다&lt;/span&gt;&lt;/b&gt;&lt;span&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;switch 문에서 타입이 자동으로 좁혀지는 이유&lt;/h3&gt;
&lt;pre id=&quot;code_1767867817150&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function processResult(task: AsyncTask) {
switch (task.state) {
case 'LOADING':
console.log('로딩 중');
break;


case 'FAILED':
console.log(`에러 발생: ${task.error.message}`);
break;


case 'SUCCESS':
console.log(`성공: ${task.response.data}`);
break;
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;case 'FAILED'&lt;/span&gt;&lt;span&gt; 블록 안에서 TypeScript는 &lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span&gt;를 &lt;/span&gt;&lt;span&gt;FailedTask&lt;/span&gt;&lt;span&gt;로 인식한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서 &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;는 optional이 아니라 &lt;/span&gt;&lt;b&gt;&lt;span&gt;반드시 존재하는 값&lt;/span&gt;&lt;/b&gt;&lt;span&gt;으로 취급된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;옵셔널 체이닝(&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;)이 전혀 필요 없다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 &lt;/span&gt;&lt;b&gt;&lt;span&gt;타입 좁히기(Type Narrowing)&lt;/span&gt;&lt;/b&gt;&lt;span&gt; 라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;꼭 알아야 할 핵심 포인트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;❗ 선택적 프로퍼티보다 상태 기반 타입 분리가 우선이다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여러 상태에 따라 서로 다른 값들이 필요하다면, 하나의 타입에 선택적 프로퍼티를 계속 추가하는 방식은 지양해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;선택적 프로퍼티는 빠르게 작성할 수는 있지만, 상태와 데이터의 관계를 타입이 보장하지 못하게 만든다. 그 결과 잘못된 조합이 런타임까지 흘러가게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 경우에는 상태(state)를 기준으로 타입을 잘게 쪼개고, 이를 유니언으로 묶는 방식이 더 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;상태에 따라 반드시 존재해야 할 값이 다르다면&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;를 붙여 해결하려 하지 말고&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;타입 자체를 분리하여 의미를 명확히 표현하는 것이 옳다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서로소 유니언 타입은 이 원칙을 가장 잘 구현한 패턴이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, &lt;u&gt;여러 경우의 수를 하나의 타입에 모두 담아야 할 때는 선택적 프로퍼티를 계속 추가하는 방식보다, &lt;/u&gt;&lt;/span&gt;&lt;u&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;나 &lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;와 같은 판별용 프로퍼티를 명시적으로 두고 각 경우를 타입 단위로 분리한 뒤 유니언으로 묶는 것이 더 안전하고 유지보수에 유리하다.&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>서로소타입</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/545</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%84%9C%EB%A1%9C%EC%86%8C-%EC%9C%A0%EB%8B%88%EC%98%A8-%ED%83%80%EC%9E%85#entry545comment</comments>
      <pubDate>Thu, 8 Jan 2026 19:26:20 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 클래스</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 클래스(Class)란 무엇인가?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;클래스에 익숙하지 않다면 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;15&quot;&gt;'청사진(Blueprint)'&lt;/b&gt; 혹은&lt;b&gt; '설계도'&lt;/b&gt;라고 생각하면 쉽다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;클래스(Class):&lt;/b&gt; 객체를 생성하기 위한 틀(설계도), 사전에 정의된 속성과 메서드를 담고 있다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;인스턴스(Instance):&lt;/b&gt; 설계도를 바탕으로 실제로 생성된 객체&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17&quot;&gt;예시: 자바스크립트의 Array&lt;/b&gt; 우리가 흔히 쓰는 배열(Array)도 일종의 패턴(청사진)이 존재한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;배열을 위한 패턴이 미리 정의되어 있고 (push, pop 등의 기능 포함)&lt;/li&gt;
&lt;li&gt;우리가 new Array()나 [ ]를 선언하는 순간,&lt;/li&gt;
&lt;li&gt;그 패턴을 바탕으로 실제 사용 가능한 배열 객체가 &lt;b data-index-in-node=&quot;28&quot; data-path-to-node=&quot;18,2,0&quot;&gt;인스턴스화&lt;/b&gt;되는 것이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;우리는 앞으로 SinglyLinkedList라는 청사진(Class)을 만들고, 이를 통해 수많은 리스트 객체(Instance)를 찍어낼 것이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;2. 자바스크립트 Class의 비밀 (Syntactic Sugar)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;사실 자바스크립트는 엄격한 의미의 '객체 지향 프로그래밍(OOP)' 언어가 아니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt; 자바스크립트는 &lt;b data-index-in-node=&quot;56&quot; data-path-to-node=&quot;21&quot;&gt;프로토타입(Prototype) 기반&lt;/b&gt;의 언어이다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;ES2015에 도입된 class 키워드는 새로운 객체 지향 모델을 만든 것이 아니라,&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;기존의 프로토타입 방식을 좀 더 쓰기 편하고 직관적으로 보이게 만든 '&lt;b&gt;문법적 설탕(Syntactic Sugar)&lt;/b&gt;&lt;/span&gt;'이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;23&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부적으로는 여전히 프로토타입 체인을 사용한다.&lt;/li&gt;
&lt;li&gt;하지만 겉모습은 Java나 Python의 Class와 유사하여 자료 구조를 정의하기 훨씬 편리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 왜 배워야할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 내에서 자료 구조의 &lt;b data-index-in-node=&quot;19&quot; data-path-to-node=&quot;9,0&quot;&gt;패턴을 정의&lt;/b&gt;하기 위해서다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스로 패턴을 한 번만 정의해 두면, 이후에는 new 키워드를 통해 개별 리스트들을 손쉽게 &lt;b data-index-in-node=&quot;86&quot; data-path-to-node=&quot;9,0&quot;&gt;인스턴스화&lt;/b&gt;하여 사용할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 클래스 선언과 생성자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스는 &lt;b&gt;객체를 생성하기 위한 청사진(설계도&lt;/b&gt;)이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,0,0&quot;&gt;클래스 이름 규칙:&lt;/b&gt; 관습적으로 대문자로 시작 (예: Student)&amp;nbsp;   &lt;b&gt;낙타대문자(Camel case)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,1,0&quot;&gt;생성자 (Constructor):&lt;/b&gt; 새로운 student 인스턴스를 &lt;u&gt;인스턴스화 시킬때 사용되는 특별한 메소드&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767269646372&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Student {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
     }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0&quot;&gt;참고:&lt;/b&gt; 반드시 클래스를 사용해야 하는 것은 아니다. 일반 객체({})를 사용할 수도 있지만, 클래스를 사용하면 코드를 더 깔끔하게 정리하고 이해하기 쉽게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;궁금증 : this 뒤에 오는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;이름(key)을 바꿔도 될까?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. this.이름을 바꾸는 경우&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;this 뒤에 오는 이름을 바꾸면, 나중에 생성된 객체 내부의 변수 이름(Key)이 바뀐다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjmo6r_yuuRAxUAAAAAHQAAAAAQQw&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;class Student {
    constructor(firstName, lastName) {
        // 'this.firstName'을 'this.englishName'으로 변경
        this.englishName = firstName; 
        this.lastName = lastName;
    }
}

const student1 = new Student(&quot;Sehyeon&quot;, &quot;Yang&quot;);

// 사용할 때 바뀐 이름으로 불러야 한다.
console.log(student1.englishName); // &quot;sehyun&quot; 출력
console.log(student1.firstName);   // undefined (이런 속성은 없음)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 매개변수(firstName)를 바꾸는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;반대로 괄호 안의 매개변수 이름을 바꾸고, this 쪽은 그대로 둘 수도 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjmo6r_yuuRAxUAAAAAHQAAAAAQRA&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Student {
    // 1. 매개변수 이름을 'name'으로 받음
    constructor(name, lastName) {
        // 2. 들어온 'name'을 객체의 'firstName' 속성에 넣음
        this.firstName = name; 
        this.lastName = lastName;
    }
}

const student2 = new Student(&quot;Gildong&quot;, &quot;Hong&quot;);
console.log(student2.firstName); // &quot;Gildong&quot; 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;왜 보통 똑같이 쓸까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;개발자들은 &lt;b data-index-in-node=&quot;6&quot; data-path-to-node=&quot;12&quot;&gt;헷갈리지 않기 위해서&lt;/b&gt; 관습적으로 이름을 똑같이 맞춘다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;this.firstName = firstName;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 쓰면 &lt;b&gt;&quot;외부에서 받은 firstName을 내 속성 firstName에 넣는다&quot;&lt;/b&gt;라는 의도가 명확해지기 때문이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;하지만 기능적으로는 서로 다른 존재이므로 필요하다면 언제든 다른 이름을 사용해도 된다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;새로운 Student 인스턴스를 생성할 때는 이름과 성(데이터)을 제공하면 된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;클래스 내부의 생성자(constructor)가 실행되면서,&amp;nbsp;&lt;b data-index-in-node=&quot;51&quot; data-path-to-node=&quot;5&quot;&gt;전달받은 값을 그 인스턴스의 this.firstName과 this.lastName 속성에 저장&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;  이 과정은 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;'새로운 인스턴스가 생성될 때, 전달된 데이터들을 해당 개별 객체(인스턴스)의 고유한 속성으로 할당하는 행위'&lt;/span&gt;라고 정의할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;2. 클래스로 객체 생성하기=&amp;gt; 인스턴스화&lt;/h2&gt;
&lt;pre id=&quot;code_1767270609710&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Student {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
     }
}

let firstStudent = new Student(&quot;Colt&quot;, &quot;Steele&quot;);
let secondStudent = new Student(&quot;Blue&quot;, &quot;Steele&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;클래스(설계도)를 정의했다면, 이제&lt;u&gt; new 키워드를 사용하여 실제 객체(인스턴스)를 생성&lt;/u&gt;해야 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,0,0&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;new&lt;/span&gt; 키워드:&lt;/b&gt; &lt;u&gt;클래스로부터 새로운 객체를 생성&lt;/u&gt;한다. 이때 constructor가 &lt;b data-index-in-node=&quot;17&quot; data-path-to-node=&quot;4,0&quot;&gt;자동으로 작동&lt;/b&gt;해서 방금 만든 빈 객체에 우리가 넘겨준 재료(데이터)를 &lt;b data-index-in-node=&quot;57&quot; data-path-to-node=&quot;4,0&quot;&gt;알아서 채워 넣어준다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767270805948&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 인스턴스 생성 예시
let firstStudent = new Student(&quot;Colt&quot;, &quot;Steele&quot;);
let secondStudent = new Student(&quot;Blue&quot;, &quot;Steele&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Student 클래스(패턴)에 기반한 새로운 객체 두 개가 생성된다.&lt;/li&gt;
&lt;li&gt;각각의 constructor가 실행되면서 전달받은 데이터가 속성으로 저장된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,1,0,0&quot;&gt;첫 번째 인스턴스(firstStudent):&lt;/b&gt; 이름은 &quot;Colt&quot;, 성은 &quot;Steele&quot;로 설정됨.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,1,1,0&quot;&gt;두 번째 인스턴스(secondStudent):&lt;/b&gt; 이름은 &quot;Blue&quot;, 성은 &quot;Steele&quot;로 설정됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 우리는 같은 구조를 가졌지만 서로 다른 데이터(Colt와 Blue)를 담고 있는 두 명의 학생 객체를 얻게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: right;&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;new 키워드 마법&lt;/b&gt;&lt;/span&gt;&amp;nbsp;  (4단계 내부 동작)&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;text-align: right;&quot;&gt;빈 객체 {} 생성 (메모리 할당)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: right;&quot;&gt;constructor 자동 호출 (this = 새 객체 바인딩)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: right;&quot;&gt;데이터 초기화 (this.prop = arg)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-align: right;&quot;&gt;완성 객체 반환 (let obj = new Class())&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;헷갈리지 말것!&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스: 설계도 바탕 실제 생성된 객체&lt;br /&gt;인스턴스화: new로 만드는 행위&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;2.1. &lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt; 키워드는 누구를 가리킬까?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;생성자 안에서 사용되는 this는 '&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;지금 당장 생성되고 있는 바로 그 객체(인스턴스)&lt;/b&gt;&lt;/span&gt;'를 가리킨다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cu3WEt/dJMcahpx6dv/TCW8VozR53vkP59JKpZJTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cu3WEt/dJMcahpx6dv/TCW8VozR53vkP59JKpZJTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cu3WEt/dJMcahpx6dv/TCW8VozR53vkP59JKpZJTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcu3WEt%2FdJMcahpx6dv%2FTCW8VozR53vkP59JKpZJTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;320&quot; height=&quot;173&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;173&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어 firstStudent를 만들 때의 this는 firstStudent 자신을 의미한다.&lt;/li&gt;
&lt;li&gt;반대로 secondStudent를 만들 때의 this는 secondStudent를 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;상황에 따라 &lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt;가 가리키는 대상이 바뀌기 때문에, 하나의 클래스(설계도)로 서로 다른 데이터를 가진 수많은 객체를 찍어낼 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;  궁금증: 생성자 안에는 무조건 &lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt;를 넣어야할까?&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. &lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt;가 반드시 필요한 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;우리가 클래스(Class)를 만드는 주된 목적은 &lt;b&gt;'데이터(상태)를 가진 객체&lt;/b&gt;'를 찍어내기 위함이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;이때 생성된 객체 자신을 가리키는 것이 바로 this다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;매개변수로 받은 값을 객체 내부에 저장해두고 계속 쓰고 싶다면, &lt;span style=&quot;color: #ee2323; background-color: #c0d1e7;&quot;&gt;반드시 this.속성명 = 값 형태&lt;/span&gt;로 연결해줘야 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjmo6r_yuuRAxUAAAAAHQAAAAAQZw&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Student {
    constructor(name) {
        this.name = name; // 여기서 this를 안 쓰면 name은 그냥 증발한다.
    }

    sayHi() {
        // this.name이 저장되어 있어야 여기서도 쓸 수 있다.
        console.log(`안녕, 나는 ${this.name}이야.`);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. &lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt;가 없어도 되는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;단순히 객체가 생성될 때 &lt;b&gt;'특정 동작'&lt;/b&gt;만 수행하고, 값을 저장할 필요가 없다면 this를 안 써도 에러는 나지 않는다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 초기화 알림 로그만 찍거나, 외부 변수를 검증만 하고 끝내는 경우다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjmo6r_yuuRAxUAAAAAHQAAAAAQaA&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Logger {
    constructor() {
        console.log(&quot;Logger 객체가 생성되었다.&quot;); // this 없이 동작만 수행
    }
}

const log = new Logger(); // &quot;Logger 객체가 생성되었다.&quot; 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;하지만 이런 경우는 드물다. 값을 저장하지 않을 거라면 굳이 클래스와 인스턴스를 만들 이유가 적기 때문이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 요약&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;결론:&lt;/b&gt; 문법적으로 필수는 아니지만, &lt;b&gt;'나중에 꺼내 쓸 데이터'&lt;/b&gt;를 저장하려면 무조건 써야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;비유:&lt;/b&gt; 붕어빵을 구울 때 팥(매개변수)을 붕어빵 틀(this) 안에 넣지 않으면, 팥은 바닥에 떨어져 사라지고 만다. 붕어빵 안에 팥을 담으려면 this.팥 = 팥 과정이 필수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;2.2. 실전 예시: &quot;Kitty&quot; 만들기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;새로운 학생 &quot;Kitty&quot;를 인스턴스화하는 과정을 살펴보자.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiHr__B-emRAxUAAAAAHQAAAAAQ4AM&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let kitty = new Student(&quot;Kitty&quot;, &quot;Kat&quot;, 1);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;이 코드가 실행될 때 내부에서는 이런 일이 일어난다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt;의 지정:&lt;/b&gt; 자바스크립트는 &quot;지금부터 this는 방금 만든 kitty 객체야&quot;라고 인식한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;데이터 할당:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;this.firstName에는 전달받은 &quot;Kitty&quot;가 들어간다.&lt;/li&gt;
&lt;li&gt;this.lastName에는 &quot;Kat&quot;이 들어간다.&lt;/li&gt;
&lt;li&gt;this.grade에는 &quot;1&quot;이 들어간다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 kitty라는 변수에는 이름, 성, 학년 정보가 꽉 채워진 객체가 저장된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;2.3. &lt;span style=&quot;color: #0593d3;&quot;&gt;new&lt;/span&gt; 키워드의 숨겨진 마법  &lt;/h3&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;우리는 코드를 짤 때 Student.constructor()라고 직접 호출하지 않는다. 그저 new Student(...)라고 썼을 뿐이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span style=&quot;color: #0593d3;&quot;&gt;new&lt;/span&gt; 키워드의 마법이 발동한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;자동 호출:&lt;/b&gt; new 키워드를 사용하면, 자바스크립트 엔진이 알아서 &quot;&lt;b&gt;아, 이 클래스의 constructor(생성자)를 실행하라는 뜻이구나!&quot;&lt;/b&gt;라고 이해하고 생성자를 자동으로 실행시킨다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;초기화:&lt;/b&gt; 덕분에 우리가 전달한 데이터들이 생성자로 넘겨지고, 객체 생성과 동시에 초기값이 세팅된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;3.   작성 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,0,0&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt; 설명 시:&lt;/b&gt; &quot;나(this)는 지금 만들어지는 녀석이야!&quot;라고 객체가 스스로를 가리키는 이미지를 상상하게 하면 이해가 쉽다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,1,0&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;new&lt;/span&gt; 설명 시:&lt;/b&gt; &quot;우리가 직접 생성자를 부르지 않아도, new가 알아서 연결해 주는 '자동문' 혹은 '스위치' 역할을 한다&quot;고 비유하면 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 인스턴스 메소드&lt;/h2&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;인스턴스 메서드는 &lt;b&gt;특정한 단일 인스턴스(객체)&lt;/b&gt;에 적용되는 기능을 말한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 자바스크립트의 배열(Array)을 생각해보자.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;3,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Array라는 클래스(패턴)가 있고, data라는 실제 배열 객체(인스턴스)가 있다.&lt;/li&gt;
&lt;li&gt;data.push(99)를 실행하면 &lt;u&gt;data는 하나의 인스턴스, push는 하나의 메소드&lt;/u&gt;이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;push 메서드는 data라는 &lt;b data-index-in-node=&quot;38&quot; data-path-to-node=&quot;3,0,1,1,0&quot;&gt;특정 인스턴스&lt;/b&gt;에서만 동작한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이것이 바로 &lt;u&gt;인스턴스 메서드&lt;/u&gt;다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;앞으로 우리는 단방향 연결 리스트(Singly Linked List) 등을 구현할 때 push, pop, reverse와 같은 수많은 인스턴스 메서드를 정의한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;1.1.&amp;nbsp; 예제: Student 클래스 확장하기&lt;/h3&gt;
&lt;h4 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size20&quot;&gt;1.2. fullName 메서드&lt;/h4&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;학생의 이름과 성을 합쳐서 반환하는 간단한 메서드다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiHr__B-emRAxUAAAAAHQAAAAAQnQQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;class Student {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
     }
     	fullName() {
    	return `Your full name is ${this.firstName} ${this.lastName}`;
	}
}

let firstStudent = new Student(&quot;Colt&quot;, &quot;Steele&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1767274058877&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fullName() {
    	return `Your full name is ${this.firstName} ${this.lastName}`;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fullName 메서드 내부의&lt;u&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt; this&lt;/span&gt;는 메서드를 호출한 특정 인스턴스(객체)&lt;/u&gt;를 가리킨다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,0,0&quot;&gt;firstStudent.fullName()을 호출할 경우:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;3,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여기서의 this는 &lt;b data-index-in-node=&quot;11&quot; data-path-to-node=&quot;3,0,1,0,0&quot;&gt;firstStudent 객체&lt;/b&gt;가 된다.&lt;/li&gt;
&lt;li&gt;따라서 ${this.firstName}은 firstStudent의 이름인 &lt;b&gt;&quot;Colt&quot;&lt;/b&gt;가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,1,0&quot;&gt;만약 secondStudent라는 다른 객체를 만들어 호출할 경우:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;3,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;secondStudent.fullName()을 실행하면, 이때의 this는 &lt;b data-index-in-node=&quot;42&quot; data-path-to-node=&quot;3,1,1,0,0&quot;&gt;secondStudent 객체&lt;/b&gt;로 바뀐다.&lt;/li&gt;
&lt;li&gt;따라서 ${this.firstName}은 secondStudent의 이름(예: &quot;Blue&quot;)이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;this&lt;/span&gt;는 고정된 값이 아니라, &lt;b data-index-in-node=&quot;25&quot; data-path-to-node=&quot;4&quot;&gt;누가 호출했느냐에 따라 가리키는 대상이 바뀌는 대명사&lt;/b&gt;와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덕분에 하나의 메서드(fullName)를 여러 인스턴스가 돌려가며 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size20&quot;&gt;1.3. markLate 메서드 (지각 횟수 관리)&lt;/h4&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;학생의 지각 횟수를 기록하고, 특정 횟수가 넘어가면 경고 메시지를 반환하는 메서드다.&lt;/p&gt;
&lt;pre id=&quot;code_1767274428245&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Student {
    constructor(firstName, lastName, year) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.grade = year;
        this.tardies = 0;
     }
     	fullName() {
    	return `Your full name is ${this.firstName} ${this.lastName}`;
	}
    	markLate() {
    	this.tardies += 1; // 지각 횟수 1 증가
    	if (this.tardies &amp;gt;= 3) {
        	return &quot;YOU ARE EXPELLED!!!!&quot;; // 3번 이상이면 퇴학 메시지
    }
    	return `${this.firstName} ${this.lastName} has been late ${this.tardies} times`;
	}

}

let firstStudent = new Student(&quot;Colt&quot;, &quot;Steele&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;먼저 생성자(constructor)에 this.tardies = 0; 속성을 추가하여 초기 지각 횟수를 0으로 설정한다.&lt;/li&gt;
&lt;li&gt;markLate 메서드를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiHr__B-emRAxUAAAAAHQAAAAAQngQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;markLate() {
    this.tardies += 1; // 지각 횟수 1 증가
    if (this.tardies &amp;gt;= 3) {
        return &quot;YOU ARE EXPELLED!!!!&quot;; // 3번 이상이면 퇴학 메시지
    }
    return `${this.firstName} ${this.lastName} has been late ${this.tardies} times`;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;이제 firstStudent.markLate()를 실행할 때마다 해당 학생의 지각 횟수가 증가하고, 3번이 되면 퇴학 메시지가 출력된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size20&quot;&gt;1.4. addScore 및 calculateAverage 메서드 (점수 관리)&lt;/h4&gt;
&lt;pre id=&quot;code_1767274600004&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Student {
    constructor(firstName, lastName, year) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.grade = year;
        this.tardies = 0;
    }

    fullName() {
        return `Your full name is ${this.firstName} ${this.lastName}`;
    }

    markLate() {
        this.tardies += 1; // 지각 횟수 1 증가
        if (this.tardies &amp;gt;= 3) {
            return &quot;YOU ARE EXPELLED!!!!&quot;; // 3번 이상이면 퇴학 메시지
        }
        return `${this.firstName} ${this.lastName} has been late ${this.tardies} times`;
    }

    addScore(score) {
        this.scores.push(score); // 인자로 받은 점수를 배열에 추가
        return this.scores;
    }

    calculateAverage() {
        // reduce를 사용하여 점수 총합 구하기
        let sum = this.scores.reduce(function(a, b) {
            return a + b;
        });
        return sum / this.scores.length; // 평균 반환
    }
}

let firstStudent = new Student(&quot;Colt&quot;, &quot;Steele&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;배열(Array)을 속성으로 갖고, 이를 조작하는 메서드도 만들 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;생성자에 this.scores = [];를 추가하여 빈 점수 배열을 만든다.&lt;/li&gt;
&lt;li&gt;점수를 추가하는 addScore와 평균을 구하는 calculateAverage를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiHr__B-emRAxUAAAAAHQAAAAAQnwQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;addScore(score) {
    this.scores.push(score); // 인자로 받은 점수를 배열에 추가
    return this.scores;
}

calculateAverage() {
    // reduce를 사용하여 점수 총합 구하기
    let sum = this.scores.reduce(function(a, b) { return a + b; });
    return sum / this.scores.length; // 평균 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size26&quot;&gt;2. 왜 메서드를 사용하는가?&lt;/h2&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;물론 student.scores.push(90)처럼 외부에서 직접 데이터에 접근할 수도 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b data-index-in-node=&quot;57&quot; data-path-to-node=&quot;21&quot;&gt;클래스 내부에 메서드를 정의하여 사용하는 것이 관습적이며 안전하다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드는 데이터에 접근하는 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;22,0,0&quot;&gt;인터페이스(Interface)&lt;/b&gt; 역할을 한다.&lt;/li&gt;
&lt;li&gt;사용자가 데이터를 직접 건드리는 실수를 줄이고, 정해진 방식대로만 데이터를 조작하도록 유도할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;요약 ✨&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;24&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,0,0&quot;&gt;인스턴스 메서드&lt;/b&gt;는 개별 객체(인스턴스)의 데이터(this.firstName, this.scores 등)에 접근하고 조작하는 함수다.&lt;/li&gt;
&lt;li&gt;앞으로 자료 구조를 구현할 때, 데이터를 추가(push)하거나 삭제(pop)하는 등의 모든 기능은 이 인스턴스 메서드로 구현된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정적 메소드(Static Method)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;지금까지 배운 인스턴스 메소드는 개별 객체(인스턴스)에 종속된 기능이었다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;반면, 정적 메소드는 &lt;b data-index-in-node=&quot;56&quot; data-path-to-node=&quot;2&quot;&gt;클래스 자체에 속하는 기능&lt;/b&gt;으로, 개별 인스턴스와는 무관하게 동작한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;3&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,0,0&quot;&gt;정의:&lt;/b&gt; 메소드 이름 앞에 static 키워드를 붙여 정의( &lt;b&gt;static키워드는 클래스의 static메소드를 정의한다. )&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,1,0&quot;&gt;호출 방식:&lt;/b&gt; 클래스 인스턴스가 아닌 &lt;b data-index-in-node=&quot;20&quot; data-path-to-node=&quot;3,1,0&quot;&gt;클래스 이름을 통해 직접 호출( &lt;b&gt;static 메소드는 클래스의 인스턴스화 없이도 호출 o, 클래스 인스턴스를 통해 호출 x )&lt;/b&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;3,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: Student.enrollStudents() (O) / firstStudent.enrollStudents() (X)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;3,2,0&quot;&gt;용도:&lt;/b&gt; 주로 어플리케이션의 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;3,2,0&quot;&gt;유틸리티(Utility) 함수&lt;/b&gt;나 헬퍼(Helper) 기능을 만들 때 사용한다. 개별 데이터가 아닌 전체적인 관리나 계산 기능 등에 적합하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4&quot;&gt;예제 1: 학생 등록 기능&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiHr__B-emRAxUAAAAAHQAAAAAQtQU&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;class Student {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
	// [인스턴스 메서드] 개별 학생의 이름을 반환 (this 사용 O)
    fullName() {
        return `Your full name is ${this.firstName} ${this.lastName}`;
    }
    
	// [정적 메서드] 학생들을 등록하는 유틸리티 기능 (this 사용 X)
    static enrollStudents(...students) {
        // 아마도 이곳에서 이메일을 보내게 될 것
    }
}

let firstStudent = new Student(&quot;Colt&quot;, &quot;Steele&quot;);
let secondStudent = new Student(&quot;Blue&quot;, &quot;Steele&quot;);

Student.enrollStudents([firstStudent, secondStudent])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;enrollStudents라는 메서드를 만들어보자.&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;이 기능은 특정 학생 한 명이 수행하는 것이 아니라, '학생 목록'을 받아 처리하는 학교(클래스) 차원의 기능이므로 static으로 정의하는 것이 적절하다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;가장 중요한 점은 &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;12&quot;&gt;호출하는 주체&lt;/b&gt;가 다르다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;❌ 잘못된 호출 (인스턴스로 호출 불가)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;firstStudent.enrollStudents()&lt;/li&gt;
&lt;li&gt;개별 학생(인스턴스)은 정적 메서드를 가지고 있지 않기 때문에 에러가 발생하거나 동작하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;✅ 올바른 호출 (클래스 이름으로 호출)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Student.enrollStudents([firstStudent, secondStudent])&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,1,1,0&quot;&gt;대문자 'S'로 시작하는 클래스 이름&lt;/b&gt;을 통해 직접 호출해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;fullName이 &quot;내(Instance) 이름은 무엇인가?&quot;를 묻는 것이라면, enrollStudents는 &quot;학교(Class)야, 이 학생들을 등록해줘&quot;라고 명령하는 것과 같다. 자료 구조를 구현할 때 주로 헬퍼 함수나 유틸리티 기능을 만들 때 이 static 메서드를 사용하게 된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6&quot;&gt;예제 2: 두 점 사이의 거리 계산 (Point 클래스)&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;좌표평면의 점을 나타내는 Point 클래스에서, 두 점 사이의 거리를 구하는 기능은 특정 점 하나에 종속되기보다 일반적인 유틸리티 기능에 가깝다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiHr__B-emRAxUAAAAAHQAAAAAQtgU&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static distance(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        return Math.hypot(dx, dy); // 거리 계산 공식
    }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

// 클래스 이름을 통해 호출하며, 인스턴스(p1, p2)를 인자로 전달함
Point.distance(p1, p2);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X축과 Y축이 있는 좌표 평면을 상상해 보자. 우리는 이곳에 점을 찍기 위해 Point라는 클래스를 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1767278455860&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;두 점 사이의 거리는 누가 구해야 할까?&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;이제 p1과 p2 사이의 거리를 구하는 기능(distance)이 필요하다. 여기서 설계의 고민이 시작된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;방법 A (인스턴스 메서드):&lt;/b&gt; p1.distance(p2)
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;p1아, 너랑 p2 사이의 거리를 재봐.&quot;&lt;/li&gt;
&lt;li&gt;가능은 하지만, 거리를 재는 행위가 꼭 p1만의 책임일까?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;방법 B (정적 메서드):&lt;/b&gt; Point.distance(p1, p2)
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;Point(점)라는 개념을 담당하는 계산기야, p1과 p2 사이의 거리를 구해줘.&quot;&lt;/li&gt;
&lt;li&gt;이것은 특정 점 하나에 종속된 기능이라기보다,&lt;b&gt; '점들을 데리고 수행하는 수학적 유틸리티'&lt;/b&gt;에 가깝다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;객체 지향 프로그래밍에서 코드를 논리적으로 구성하기 위해서는 &lt;b data-index-in-node=&quot;34&quot; data-path-to-node=&quot;12&quot;&gt;방법 B&lt;/b&gt;가 더 적합하다. 그래서 우리는 이 기능을 static 메서드로 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1767278506733&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    // static 키워드를 붙여 유틸리티 함수로 정의
    static distance(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        return Math.hypot(dx, dy); // 수학 공식을 이용한 거리 계산
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 거리를 구해보자. 중요한 건 &lt;b data-index-in-node=&quot;19&quot; data-path-to-node=&quot;17&quot;&gt;인스턴스가 아닌 클래스 이름&lt;/b&gt;을 부른다.&lt;/p&gt;
&lt;pre id=&quot;code_1767278538208&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

// ✅ 올바른 호출: 클래스(Point)에게 시킨다.
console.log(Point.distance(p1, p2)); 

// ❌ 틀린 호출: p1은 distance라는 메서드를 모른다.
// p1.distance(p2); -&amp;gt; Error 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;물론 인스턴스 메서드로 구현해도 프로그램은 돌아간다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;하지만 static을 사용하는 이유는 코드를 더 &lt;b data-index-in-node=&quot;57&quot; data-path-to-node=&quot;20&quot;&gt;논리적이고 깔끔하게 정리하기 위해서&lt;/b&gt;다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터(x, y)는 &lt;b&gt;인스턴스(p1, p2)&lt;/b&gt;가 관리하고,&lt;/li&gt;
&lt;li&gt;데이터를 가지고 계산하는 도구(거리 측정)는 &lt;b&gt;클래스(Point)&lt;/b&gt;가 관리하는 구조다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;b data-index-in-node=&quot;4&quot; data-path-to-node=&quot;22&quot;&gt;개별 데이터와 무관한 헬퍼(Helper)나 유틸리티(Utility) 기능&lt;/b&gt;을 만들 때 static을 적극 활용하면 좋다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;1. 자료 구조에서의 활용&lt;/h3&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;사실 앞으로 진행될 자료 구조 강의에서는 &lt;b data-index-in-node=&quot;23&quot; data-path-to-node=&quot;9&quot;&gt;인스턴스 메소드&lt;/b&gt;가 훨씬 더 많이 사용된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 리스트의 push, pop, reverse 등은 모두 특정 리스트(인스턴스)의 데이터를 조작해야 하기 때문이다.&lt;/li&gt;
&lt;li&gt;정적 메소드는 드물게 사용되지만, 클래스 문법의 완전한 이해를 위해 알아두는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;자료 구조 클래스를 설계할 때의 가이드라인을 보여주는 의사 코드&lt;/h3&gt;
&lt;pre id=&quot;code_1767278887642&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class DataStructure {
    constructor() {
        // 어떤 기본 속성들을 가져야 할까?
    }

    someInstanceMethod() {
        // 이 클래스로부터 생성된 각 객체는 무엇을 할 수 있어야 할까?
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;this 키워드의 동작 방식&lt;/h3&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 this는 상황에 따라 다르게 동작하여 혼란을 주곤 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;하지만&lt;b&gt; Class 내부(생성자 및 인스턴스 메서드)에서의 this&lt;/b&gt;는 명확하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;규칙:&lt;/b&gt; this는 클래스로부터 생성된 &lt;b&gt;실제 객체(인스턴스)&lt;/b&gt;를 가리킨다.&lt;/li&gt;
&lt;li&gt;즉, 우리가 new 키워드로 만든 바로 그 '개별 객체'를 참조한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✨ Class 문법 4단계 요약&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;클래스(Class):&lt;/b&gt; 객체(인스턴스)를 생성하기 위한 &lt;b&gt;청사진(Blueprint)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;인스턴스화(Instantiation):&lt;/b&gt; (이런 클래스들은) new 키워드를 사용하여 실제 객체를 생성한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,2,0&quot;&gt;생성자(Constructor):&lt;/b&gt; 인스턴스가 생성될 때 자동으로 실행되는 특별한 메소드로, 초기 속성 값을 설정하는 데 사용된다. (생성자 함수는 클래스가 인스턴스화할때 동작하는 특별한 함수)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;new를 통해 Studnet클래스를 인스턴스화 시키게 되면 Stuendt의 생성자가 먼저 동작한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,3,0&quot;&gt;this 키워드:&lt;/b&gt; 인스턴스 메소드나 생성자 내부에서 사용될 때, &lt;b data-index-in-node=&quot;36&quot; data-path-to-node=&quot;13,3,0&quot;&gt;개별 인스턴스(객체) 자신&lt;/b&gt;을 가리킨다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,4,0&quot;&gt;메소드 종류:&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;인스턴스 메서드 (Instance Methods):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적인 객체의 메서드처럼 정의하며, new로 생성된 **개별 인스턴스(객체)**의 데이터에 접근하고 조작한다. (자료 구조 구현 시 가장 많이 사용됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;클래스 메서드 (Class Methods / Static Methods):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,1,0,0&quot;&gt;static 키워드&lt;/b&gt;를 사용하여 정의한다.&lt;/li&gt;
&lt;li&gt;개별 인스턴스가 아닌 &lt;b data-index-in-node=&quot;12&quot; data-path-to-node=&quot;7,1,1,1,0&quot;&gt;클래스 자체&lt;/b&gt;에 속하며, 주로 헬퍼나 유틸리티 기능으로 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  알고리즘&amp;amp;자료구조</category>
      <category>This</category>
      <category>객체</category>
      <category>메소드</category>
      <category>알고리즘</category>
      <category>어렵다</category>
      <category>인스턴스</category>
      <category>인스턴스메소드</category>
      <category>자료구조</category>
      <category>자바스크립트</category>
      <category>클래스</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/544</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%81%B4%EB%9E%98%EC%8A%A4#entry544comment</comments>
      <pubDate>Thu, 1 Jan 2026 23:57:44 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 자료구조</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-path-to-node=&quot;3&quot;&gt;1. 자료 구조의 종류&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-path-to-node=&quot;5&quot;&gt;
&lt;li&gt;단방향/양방향 연결 리스트 (Singly/Doubly Linked Lists)&lt;/li&gt;
&lt;li&gt;이진 검색 트리 (Binary Search Trees), 이진 힙 (Binary Heaps)&lt;/li&gt;
&lt;li&gt;그래프 (Graphs - 방향/비방향, 가중/비가중)&lt;/li&gt;
&lt;li&gt;스택 (Stacks), 큐 (Queues), 우선순위 큐 (Priority Queues)&lt;/li&gt;
&lt;li&gt;해시 테이블 (Hash Tables)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-path-to-node=&quot;6&quot;&gt;2. 자료 구조란 무엇인가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-path-to-node=&quot;7&quot;&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;7,0,0&quot; data-index-in-node=&quot;0&quot;&gt;정의:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값(Value)들의 모음이자, 그 값들 사이의 관계(예: 순서, 부모-자식 관계 등)를 포함하는 구조&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;7,1,0&quot; data-index-in-node=&quot;0&quot;&gt;기능:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터의 삽입, 제거, 접근, 정렬 등을 수행하는 고유의 메소드(Push, Pop 등)를 가진다.&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;7,2,0&quot; data-index-in-node=&quot;0&quot;&gt;구현:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이미 사용해 본 배열(Array)이나 객체(Object)처럼, 우리만의 구조를 클래스 형태로 정의하고 필요한 기능을 추가한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-path-to-node=&quot;8&quot;&gt;3. 왜 다양한 자료 구조가 필요한가?&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-path-to-node=&quot;9&quot;&gt;&quot;가장 좋은 하나의 자료 구조&quot;는 없다. 문제의 상황에 따라 적합한 구조가 다르다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-path-to-node=&quot;10&quot;&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;10,0,0&quot; data-index-in-node=&quot;0&quot;&gt;지도/GPS (최단 경로):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;그래프(Graph)가 적합하다.&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;10,1,0&quot; data-index-in-node=&quot;0&quot;&gt;정렬된 리스트의 앞단 삽입/삭제:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;배열(Array)은 인덱스 재정렬로 인해 비효율적이므로, 연결 리스트(Linked List)가 유리하다&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;10,2,0&quot; data-index-in-node=&quot;0&quot;&gt;HTML/DOM 조작:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;트리(Tree) 구조가 사용된다.&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;10,3,0&quot; data-index-in-node=&quot;0&quot;&gt;작업 스케줄링 (우선순위):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이진 힙(Binary Heap)이나 우선순위 큐가 적합하다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>  알고리즘&amp;amp;자료구조</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/543</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0#entry543comment</comments>
      <pubDate>Thu, 1 Jan 2026 22:55:14 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입 좁히기 (Type Narrowing)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EC%A2%81%ED%9E%88%EA%B8%B0-Type-Narrowing</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffd1dc;&quot;&gt;타입 좁히기는 조건문 등을 이용해 &lt;b data-index-in-node=&quot;19&quot; data-path-to-node=&quot;3&quot;&gt;넓은 타입(유니온 타입 등)에서 더 구체적이고 좁은 타입으로 범위를 축소하는 과정&lt;/b&gt;을 말한다. &lt;/span&gt;  &lt;u&gt;컴파일러에게 특정 코드 블록 내에서는 변수가 특정 타입임을 보장할 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이때 타입을 좁히기 위해 사용하는 조건식 표현(typeof, instanceof 등)을 &lt;b&gt;타입 가드(Type Guard)&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. typeof 타입 가드&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트의 기본 연산자인 typeof를 사용하여&lt;b&gt; 원시 타입(Primitive Type)&lt;/b&gt;을 좁힐 때 주로 사용한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiilZiR-OeRAxUAAAAAHQAAAAAQzAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;function func(value: number | string) {
  // ❌ Error: value가 number인지 string인지 확신할 수 없음
  // value.toFixed(); 

  if (typeof value === &quot;number&quot;) {
    // ✅ 이 블록 안에서 value는 'number' 타입으로 보장됨
    console.log(value.toFixed());
  } else if (typeof value === &quot;string&quot;) {
    // ✅ 이 블록 안에서 value는 'string' 타입으로 보장됨
    console.log(value.toUpperCase());
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;2. instanceof 타입 가드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9&quot;&gt;내장 클래스&lt;/b&gt;(Date 등)나 &lt;b data-index-in-node=&quot;16&quot; data-path-to-node=&quot;9&quot;&gt;직접 만든 클래스&lt;/b&gt;의 인스턴스인지 확인할 때 사용한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;단, interface나 type 별칭으로 만든 커스텀 타입은 런타임에 사라지므로 instanceof를 사용할 수 없다.&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiilZiR-OeRAxUAAAAAHQAAAAAQzQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;function func(value: number | string | Date | null) {
  if (typeof value === &quot;number&quot;) {
    console.log(value.toFixed());
  } else if (typeof value === &quot;string&quot;) {
    console.log(value.toUpperCase());
  } else if (value instanceof Date) {
    // ✅ 이 블록 안에서 value는 'Date' 객체로 보장됨
    console.log(value.getTime());
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;3. in 타입 가드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;직접 정의한 &lt;b&gt;객체 타입(Interface, Type Alias)&lt;/b&gt;을 좁혀야 할 때 사용한다. &quot;속성명&quot; in 객체 형태의 연산자를 사용하여, 해당 객체에 특정 프로퍼티가 존재하는지 확인하는 방식이다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiilZiR-OeRAxUAAAAAHQAAAAAQzgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type Person = {
  name: string;
  age: number;
};

function func(value: number | string | Date | null | Person) {
  if (typeof value === &quot;number&quot;) {
    console.log(value.toFixed());
  } else if (typeof value === &quot;string&quot;) {
    console.log(value.toUpperCase());
  } else if (value instanceof Date) {
    console.log(value.getTime());
  } else if (value &amp;amp;&amp;amp; &quot;age&quot; in value) {
    // ✅ value가 null이 아니고, 'age' 프로퍼티가 있다면 Person 타입으로 보장됨
    console.log(`${value.name}은 ${value.age}살 입니다`);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;14&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;14,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0&quot;&gt;참고:&lt;/b&gt; value &amp;amp;&amp;amp; ... 검사가 필요한 이유는 null 또한 typeof 연산 결과가 'object'이지만, in 연산자를 사용할 수 없기 때문이다. 따라서 값이 존재하는지(null이 아닌지) 먼저 확인해야 안전하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>IN</category>
      <category>instanceof</category>
      <category>typeof</category>
      <category>typescript</category>
      <category>타입스크립트</category>
      <category>타입좁히기</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/541</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EC%A2%81%ED%9E%88%EA%B8%B0-Type-Narrowing#entry541comment</comments>
      <pubDate>Wed, 31 Dec 2025 23:05:38 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입 단언 (Type Assertion)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EB%8B%A8%EC%96%B8-Type-Assertion</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트의 타입 추론에 의존하지 않고, 개발자가 &lt;b&gt;&quot;내가 이 값의 타입을 더 잘 알고 있으니 나를 믿어라&quot;&lt;/b&gt;라고 컴파일러에게 직접 타입을 지시하는 문법이다. =&amp;gt; 타입 단언을 사용할때는&amp;nbsp;&lt;b&gt;확신할때만 사용하자!&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 기본 문법과 사용 사례&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;변수 초기화 시 빈 객체를 할당하거나, 초과 프로퍼티 검사를 우회해야 할 때 유용&lt;/span&gt;하다. &lt;b&gt;값 as 타입 문법&lt;/b&gt;을 사용한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6&quot;&gt;사례 1: 빈 객체 초기화&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 기본적으로 빈 객체({})를 특정 타입(Person)에 할당하는 것을 허용하지 않는다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;이때 타입 단언을 사용하면 빈 객체로 초기화한 뒤 프로퍼티를 채워 넣을 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQ4wE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;type Person = {
  name: string;
  age: number;
};

// ❌ Error: 빈 객체는 Person 타입이 아님
// let person: Person = {};

// ✅ OK: 빈 객체를 Person 타입으로 단언
let person = {} as Person;
person.name = &quot;&quot;;
person.age = 23;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8&quot;&gt;사례 2: 초과 프로퍼티 검사 우회&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;객체 리터럴 사용 시 발생하는 초과 프로퍼티 검사를 피할 때도 사용된다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQ5AE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;type Dog = {
  name: string;
  color: string;
};

// breed는 Dog 타입에 없지만, 단언을 통해 검사를 무력화함
let dog: Dog = {
  name: &quot;돌돌이&quot;,
  color: &quot;brown&quot;,
  breed: &quot;진도&quot;,
} as Dog;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;2. 타입 단언의 규칙 (교집합 유무)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;무조건적인 단언이 가능한 것은 아니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;값 as 단언 &amp;larr; 단언식&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;A as B 형태의 단언이 성립하려면 &lt;b data-index-in-node=&quot;43&quot; data-path-to-node=&quot;12&quot;&gt;A가 B의 슈퍼타입이거나, 서브타입이어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;두 타입 사이에 교집합&lt;/span&gt;이 있어야 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQ5QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let num1 = 10 as never;   // ✅ OK: never는 모든 타입의 서브타입
let num2 = 10 as unknown; // ✅ OK: unknown은 모든 타입의 슈퍼타입

// ❌ Error: number와 string은 서로 겹치는 부분이 없음(서로소)
// let num3 = 10 as string;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;3. 다중 단언 (Double Assertion)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;위 규칙에 따라 number를 string으로 바로 단언할 수는 없지만, unknown을 거쳐서 강제로 변환하는 것은 가능하다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQ5gE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;// number -&amp;gt; unknown -&amp;gt; string
let num3 = 10 as unknown as string;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;unknown은 모든 타입의 슈퍼타입이므로 어떤 타입으로든 단언이 가능하다. 이를 이용해 &lt;b data-index-in-node=&quot;50&quot; data-path-to-node=&quot;17&quot;&gt;[값 &amp;rarr; unknown &amp;rarr; 원하는 타입]&lt;/b&gt; 순서로 단언하면 컴파일러의 눈을 속일 수 있다.&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;18&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;18,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0&quot;&gt;주의:&lt;/b&gt; 이는 타입스크립트의 안전장치를 완전히 해제하는 위험한 방식이므로, 불가피한 경우가 아니면 사용을 지양해야 한다.&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(이렇게 다중 단언으로 사용하면 타입스크립트를 사용할 의미가 없어진다.)&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size26&quot;&gt;4. const 단언 (as const)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;값을 상수로 사용하겠다고 단언하는 문법이다. 변수를 const로 선언하는 것과 유사하지만,&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;51&quot; data-path-to-node=&quot;21&quot;&gt;객체의 모든 프로퍼티를 readonly로 만들고 리터럴 타입으로 추론&lt;/b&gt;한다는 차이가 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQ5wE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;let num4 = 10 as const; 
// 타입이 number가 아닌 10(리터럴 타입)으로 단언됨

let cat = {
  name: &quot;야옹이&quot;,
  color: &quot;yellow&quot;,
} as const;
// 모든 프로퍼티가 readonly로 변경됨 (수정 불가)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size26&quot;&gt;5. Non-Null 단언 (!)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;값 뒤에&lt;b&gt; 느낌표(!)&lt;/b&gt;를 붙여, 해당 값이 &lt;b data-index-in-node=&quot;23&quot; data-path-to-node=&quot;25&quot;&gt;null이나 undefined가 아님을 확신&lt;/b&gt;할 때 사용한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;컴파일러에게 &lt;u&gt;&quot;이 값은 절대 비어있지 않다&quot;&lt;/u&gt;고 알리는 것이다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQ6AE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type Post = {
  title: string;
  author?: string; // 선택적 프로퍼티 (string | undefined)
};

let post: Post = {
  title: &quot;게시글1&quot;,
};

// ❌ Error: author가 undefined일 수 있음
// const len: number = post.author?.length;

// ✅ OK: author가 반드시 존재한다고 단언
const len: number = post.author!.length;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1767187707094&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌인 이유
// const len: number = post.author?.length;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post.author에 &lt;b&gt;실제로 값이 있어도&lt;/b&gt;,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트는 author?: string(옵셔널) 선언을 보고 &amp;ldquo;없을 수도 있다(= undefined일 수도 있다)&amp;rdquo;고 항상 판단한다.&lt;br /&gt;그래서 post.author?.length의 결과 타입은 number가 아니라 &lt;b&gt;number | undefined&lt;/b&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽은 &lt;b&gt;무조건 number&lt;/b&gt;여야 하는데, 오른쪽은 &lt;b&gt;undefined가 될 수도 있는 값&lt;/b&gt;이라서 오류가 난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>NonNull</category>
      <category>다중단언</category>
      <category>타입단언</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/540</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EB%8B%A8%EC%96%B8-Type-Assertion#entry540comment</comments>
      <pubDate>Fri, 19 Dec 2025 23:52:29 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입 추론 (Type Inference)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EC%B6%94%EB%A1%A0-Type-Inference</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 변수에 명시적으로 타입을 정의하지 않아도,&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;초기화된 값을 기준으로 타입을 자동으로 결정하는 &lt;b data-index-in-node=&quot;59&quot; data-path-to-node=&quot;3&quot;&gt;타입 추론(Type Inference)&lt;/b&gt; 기능을 제공한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 &lt;u&gt;모든 변수에 일일이 타입을 타이핑하는 번거로움을 줄일 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;⚠️&amp;nbsp;&lt;u&gt; 단, 함수의 매개변수처럼 추론할 근거가 없는 경우에는 추론이 불가능하며, strict 모드에서는 이를 에러로 간주할 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. 타입 추론이 발생하는 경우&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 다음과 같은 상황에서 문맥을 파악하여 타입을 &lt;b&gt;자동으로 추론한다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;1-1. 변수 초기화&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;변수 선언과 동시에 값을 할당하면, &lt;b&gt;해당 값의 타입을 기준&lt;/b&gt;으로 추론한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;객체나 배열 같은 복잡한 구조도 문제없이 추론된다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQlgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;let a = 10;       // number로 추론
let b = &quot;hello&quot;;  // string으로 추론

let c = {
  id: 1,
  name: &quot;이정환&quot;,
  profile: {
    nickname: &quot;winterlood&quot;,
  },
  urls: [&quot;https://winterlood.com&quot;],
}; 
// id, name, profile, urls 프로퍼티가 있는 객체 타입으로 자동 추론됨&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;1-2. 구조 분해 할당&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;객체나 배열을 구조 분해 할당할 때도 원본 객체의 타입을 바탕으로 추론된다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQlwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let { id, name, profile } = c;          // c의 프로퍼티 타입에 맞춰 추론
let [one, two, three] = [1, &quot;hello&quot;, true]; // number, string, boolean으로 추론
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;1-3. 함수의 반환값 &amp;amp; 기본값 매개변수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;반환값:&lt;/b&gt; return 문 다음에 오는 값을 분석하여 반환 타입을 추론한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;기본값 매개변수:&lt;/b&gt; 매개변수에 기본값(Default Value)이 설정되어 있다면, 그 값을 기준으로 타입을 추론한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQmAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;// 반환값이 string으로 추론됨
function func() {
  return &quot;hello&quot;;
}

// message는 기본값 &quot;hello&quot;에 의해 string으로 추론됨
function funcDefault(message = &quot;hello&quot;) {
  return message;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size26&quot;&gt;2. 주의해야 할 특수 상황&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;2-1. 암시적 Any와 진화&amp;nbsp;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;변수를 선언할 때 &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;19&quot;&gt;초기값을 생략&lt;/b&gt;하면, 타입스크립트는 이를 &lt;b data-index-in-node=&quot;32&quot; data-path-to-node=&quot;19&quot;&gt;암시적 any(Implicit Any)&lt;/b&gt; 타입으로 추론한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;이후 코드 흐름에 따라 변수에 할당되는 값에 맞춰 타입이 계속 변하는 현상이 발생하는데, 이를 &lt;b&gt;Any의 진화(Any Evolution)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQmQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let d; // 암시적 any 선언

d = 10;
d.toFixed(); // 이 시점에서는 number 타입으로 취급

d = &quot;hello&quot;;
d.toUpperCase(); // 이 시점에서는 string 타입으로 취급

// ❌ Error: 현재 d는 string이므로 number 메서드 사용 불가
// d.toFixed(); 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;21&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;21,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,0&quot;&gt;주의:&lt;/b&gt; 타입이 런타임에 예측 불가능하게 변할 수 있으므로, 초기값을 주지 않을 때는 명시적으로 타입을 지정하는 것이 안전하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;2-2. const와 리터럴 타입 추론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;let으로 선언한 변수와 const로 선언한 상수는 추론 방식이 다르다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;24&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,0,0&quot;&gt;let:&lt;/b&gt; 재할당이 가능하므로, 범용적인 타입(예: number, string)으로 추론된다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,1,0&quot;&gt;const:&lt;/b&gt; 재할당이 불가능하므로, 값 자체를 타입으로 하는 &lt;b data-index-in-node=&quot;34&quot; data-path-to-node=&quot;24,1,0&quot;&gt;리터럴 타입&lt;/b&gt;으로 좁게 추론된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQmgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;let num = 10;       // number 타입 (값 변경 가능)
const constNum = 10; // 10 리터럴 타입 (값 변경 불가)

let str = &quot;hello&quot;;       // string 타입
const constStr = &quot;hello&quot;; // &quot;hello&quot; 리터럴 타입
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;2-3. 최적 공통 타입&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;여러 타입이 섞인 배열을 초기화할 때, 타입스크립트는 모든 요소를 포괄할 수 있는 &lt;b data-index-in-node=&quot;46&quot; data-path-to-node=&quot;27&quot;&gt;유니온 타입&lt;/b&gt;으로 추론한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwidqvvC68mRAxUAAAAAHQAAAAAQmwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let arr = [1, &quot;string&quot;]; 
// (string | number)[] 타입으로 추론&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>타입스크립트</category>
      <category>타입추론</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/539</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EC%B6%94%EB%A1%A0-Type-Inference#entry539comment</comments>
      <pubDate>Fri, 19 Dec 2025 23:34:13 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 대수 타입 (Algebraic Type)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EB%8C%80%EC%88%98-%ED%83%80%EC%9E%85-Algebraic-Type</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Adh8Q/dJMcajgrefa/WuFVOCW882OuXOiZi9klyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Adh8Q/dJMcajgrefa/WuFVOCW882OuXOiZi9klyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Adh8Q/dJMcajgrefa/WuFVOCW882OuXOiZi9klyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAdh8Q%2FdJMcajgrefa%2FWuFVOCW882OuXOiZi9klyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;443&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;대수 타입은 &lt;u&gt;여러 개의 타입을 합성하여 만드는 새로운 타입&lt;/u&gt;을 의미한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;집합론의 개념을 차용하여 타입을 구성하며, 크게 &lt;b&gt;합집합(Union)&lt;/b&gt; 타입과 &lt;b&gt;교집합(Intersection)&lt;/b&gt; 타입으로 나뉜다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 합집합 - 유니온(Union) 타입&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cD2cPc/dJMb99LHWdc/kNKSlKMbckqms0KT6iWNJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cD2cPc/dJMb99LHWdc/kNKSlKMbckqms0KT6iWNJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cD2cPc/dJMb99LHWdc/kNKSlKMbckqms0KT6iWNJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcD2cPc%2FdJMb99LHWdc%2FkNKSlKMbckqms0KT6iWNJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;288&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;유니온 타입은&lt;span style=&quot;background-color: #f6e199;&quot;&gt; | (버티컬 바) 기호&lt;/span&gt;를 사용하여 정의하며, 나열된 타입 중 &lt;b&gt;하나라도 만족하면 되는&lt;/b&gt; 합집합의 개념을 갖는다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;1-1. 기본 타입의 유니온&lt;/h3&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;변수에 다양한 타입의 값을 저장해야 할 때 사용한다. 타입의 개수에는 제한이 없다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQhAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// string 또는 number 또는 boolean 타입 허용
let a: string | number | boolean;

a = 1;       // ✅ OK
a = &quot;hello&quot;; // ✅ OK
a = true;    // ✅ OK
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;1-2. 배열에서의 유니온&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;다양한 타입의 요소를 동시에 저장하는 배열을 정의할 때 유용하다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQhQI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;let arr: (number | string | boolean)[] = [1, &quot;hello&quot;, true];
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;1-3. 객체 타입의 유니온&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;객체 타입 간의 유니온은&lt;b&gt; &quot;적어도 하나의 타입 구조를 완벽히 만족해야 한다&quot;&lt;/b&gt;는 의미를 갖는다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQhgI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;type Dog = {
  name: string;
  color: string;
};

type Person = {
  name: string;
  language: string;
};

type Union1 = Dog | Person;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;유효한 값의 범위&lt;/b&gt; 집합의 합집합 개념에 따라 아래 세 가지 케이스가 모두 허용된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Dog 타입만 만족하는 객체 (교집합 제외 영역 A)&lt;/li&gt;
&lt;li&gt;Person 타입만 만족하는 객체 (교집합 제외 영역 B)&lt;/li&gt;
&lt;li&gt;Dog와 Person 프로퍼티를 모두 가진 객체 (교집합 영역)&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQhwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;// ✅ Case 1: Dog 타입 만족
let union1: Union1 = {
  name: &quot;돌돌이&quot;,
  color: &quot;brown&quot;,
};

// ✅ Case 2: Person 타입 만족
let union2: Union1 = {
  name: &quot;이정환&quot;,
  language: &quot;ko&quot;,
};

// ✅ Case 3: 둘 다 만족 (교집합)
let union3: Union1 = {
  name: &quot;짱구&quot;,
  color: &quot;white&quot;,
  language: &quot;jp&quot;,
};

// ❌ Error: 둘 중 어느 것도 완벽히 만족하지 못함
let union4: Union1 = {
  name: &quot;철수&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uPf4W/dJMcafkRcJZ/27WnMenZKdNuq3SJsypHEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uPf4W/dJMcafkRcJZ/27WnMenZKdNuq3SJsypHEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uPf4W/dJMcafkRcJZ/27WnMenZKdNuq3SJsypHEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuPf4W%2FdJMcafkRcJZ%2F27WnMenZKdNuq3SJsypHEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;770&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;770&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size26&quot;&gt;2. 교집합 - 인터섹션(Intersection) 타입&lt;/h2&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;인터섹션 타입은&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt; &amp;amp; (앰퍼샌드) 기호&lt;/b&gt;&lt;/span&gt;를 사용하여 정의하며, 나열된 &lt;b&gt;모든 타입을 동시에 만족해야 하는&lt;/b&gt; 교집합의 개념을 갖는다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;2-1. 기본 타입의 인터섹션&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;대다수의 기본 타입(원시 타입) 간에는 공유하는 값(교집합)이 없다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;=&amp;gt; &lt;u&gt;기본 타입끼리 교집합을 만들면 &lt;b&gt;공집합&lt;/b&gt;인 never 타입이 된다.&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQiAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;// number와 string을 동시에 만족하는 값은 존재하지 않음
let variable: number &amp;amp; string; // never 타입으로 추론됨
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;769&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQxsCE/dJMcagKPQCe/eECRBKz3CnGAVcNeKirUVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQxsCE/dJMcagKPQCe/eECRBKz3CnGAVcNeKirUVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQxsCE/dJMcagKPQCe/eECRBKz3CnGAVcNeKirUVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQxsCE%2FdJMcagKPQCe%2FeECRBKz3CnGAVcNeKirUVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;769&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;769&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size23&quot;&gt;2-2. 객체 타입의 인터섹션&lt;/h3&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;인터섹션 타입은 주로 객체 타입을 합성할 때 사용된다. 두 객체 타입을 인터섹션 하면, &lt;b&gt;두 객체의 프로퍼티를 모두 포함하는 새로운 객체 타입&lt;/b&gt;이 만들어진다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQiQI&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;type Dog = {
  name: string;
  color: string;
};

type Person = {
  name: string;
  language: string;
};

// Dog와 Person의 모든 프로퍼티를 가져야 함
type Intersection = Dog &amp;amp; Person;

let intersection1: Intersection = {
  name: &quot;개사람&quot;,
  color: &quot;brown&quot;,
  language: &quot;ko&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;즉, Intersection 타입은 name, color, language 3개의 프로퍼티를 모두 가지고 있어야 유효하다.&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>교집합</category>
      <category>대수타입</category>
      <category>유니온</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/538</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EB%8C%80%EC%88%98-%ED%83%80%EC%9E%85-Algebraic-Type#entry538comment</comments>
      <pubDate>Wed, 17 Dec 2025 16:37:26 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 객체 타입의 호환성 (Object Type Compatibility)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EA%B0%9D%EC%B2%B4-%ED%83%80%EC%9E%85%EC%9D%98-%ED%98%B8%ED%99%98%EC%84%B1-Object-Type-Compatibility</link>
      <description>&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;기본 타입과 마찬가지로 객체 타입 간의 호환성도 &lt;b&gt;슈퍼타입(부모)&lt;/b&gt;과 &lt;b&gt;서브타입(자식)&lt;/b&gt;의 관계를 기준으로 판단한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;업캐스팅 (서브 &amp;rarr; 슈퍼):&lt;/b&gt; 허용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다운캐스팅 (슈퍼 &amp;rarr; 서브):&lt;/b&gt; 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;1. 객체 간의 슈퍼-서브 타입 관계&lt;/h2&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 &lt;b&gt;프로퍼티를 기준&lt;/b&gt;으로 타입을 정의하는 &lt;b&gt;구조적 타입 시스템&lt;/b&gt;을 따른다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;슈퍼타입:&lt;/b&gt; 조건(프로퍼티)이 더 적은 타입. 더 넓은 범위를 포함한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서브타입:&lt;/b&gt; 조건(프로퍼티)이 더 많은 타입. 더 구체적인 범위를 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQ2wE&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;type Animal = { // 슈퍼타입 (조건이 적음 -&amp;gt; 집합이 큼)
  name: string;
  color: string;
};

type Dog = {    // 서브타입 (조건이 많음 -&amp;gt; 집합이 작음)
  name: string;
  color: string;
  breed: string; // 추가된 조건
};

let animal: Animal = {
  name: &quot;기린&quot;,
  color: &quot;yellow&quot;,
};

let dog: Dog = {
  name: &quot;돌돌이&quot;,
  color: &quot;brown&quot;,
  breed: &quot;진도&quot;,
};

// ✅ 업캐스팅 (허용): Dog는 Animal의 모든 조건을 만족함
animal = dog; 

// ❌ 다운캐스팅 (불가): Animal은 Dog의 조건(breed)을 만족하지 못함
// dog = animal; 
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;213&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XW8VD/dJMcafkRbJu/KEfMhv671KK7LIaBK7tbM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XW8VD/dJMcafkRbJu/KEfMhv671KK7LIaBK7tbM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XW8VD/dJMcafkRbJu/KEfMhv671KK7LIaBK7tbM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXW8VD%2FdJMcafkRbJu%2FKEfMhv671KK7LIaBK7tbM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;568&quot; height=&quot;213&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;213&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;핵심 원리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;Dog 타입이 프로퍼티 개수가 더 많아서 '더 큰 타입'처럼 보일 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;하지만 집합의 관점에서 보면, &lt;b&gt;조건(프로퍼티)이 많을수록 해당 조건을 만족하는 객체의 수는 줄어든다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;=&amp;gt; &lt;u&gt;프로퍼티가 더 구체적인 Dog가 부분집합(서브타입)이 된다.&lt;/u&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;초과 프로퍼티 검사 (Excess Property Check)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;객체 타입의 호환성에 따르면, 서브타입의 객체를 슈퍼타입 변수에 할당하는 것(업캐스팅)은 가능해야 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;객체 리터럴을 직접 할당할 때&lt;/b&gt;는 예외가 발생한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;1. 현상 및 원인&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQ3AE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;type Book = {
  name: string;
  price: number;
};

// ❌ Error: 객체 리터럴로 직접 할당 시 오류 발생
let book2: Book = {
  name: &quot;한 입 크기로 잘라먹는 리액트&quot;,
  price: 33000,
  skill: &quot;reactjs&quot;, // Book 타입에 없는 초과 프로퍼티
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;위 코드는 논리적으로 업캐스팅이지만 에러가 발생한다. 이는 타입스크립트가 &lt;b&gt;변수를 객체 리터럴로 초기화할 때&lt;/b&gt; 발동시키는 &lt;b&gt;초과 프로퍼티 검사&lt;/b&gt; 때문이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;이 기능은 개발자가 의도하지 않은 프로퍼티를 실수로 작성하는 것을 방지하기 위한 안전장치다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;2. 해결 방법 (검사 우회)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;초과 프로퍼티 검사는 &lt;b&gt;객체 리터럴을 직접 사용하는 경우에만&lt;/b&gt; 발동한다. 따라서 객체를 다른 변수에 먼저 저장한 뒤 할당하면 검사를 피할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQ3QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;type ProgrammingBook = {
  name: string;
  price: number;
  skill: string;
};

let programmingBook: ProgrammingBook = {
  name: &quot;한 입 크기로 잘라먹는 리액트&quot;,
  price: 33000,
  skill: &quot;reactjs&quot;,
};

// ✅ OK: 변수에 담아 할당하면 초과 프로퍼티 검사가 발생하지 않음 (일반적인 업캐스팅)
let book3: Book = programmingBook;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;3. 함수 매개변수에서의 동작&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;함수에 인수를 전달할 때도 객체 리터럴을 직접 넣으면 검사가 발동한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwj_2-Dm_sORAxUAAAAAHQAAAAAQ3gE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;function func(book: Book) {}

// ❌ Error: 객체 리터럴 직접 전달 (초과 프로퍼티 검사 발동)
func({
  name: &quot;리액트&quot;,
  price: 33000,
  skill: &quot;reactjs&quot;,
});

// ✅ OK: 변수로 전달 (검사 미발동)
func(programmingBook);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>  TypeScript</category>
      <category>객체타입</category>
      <category>다운캐스팅</category>
      <category>업캐스팅</category>
      <category>캐체타입의호환성</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/537</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EA%B0%9D%EC%B2%B4-%ED%83%80%EC%9E%85%EC%9D%98-%ED%98%B8%ED%99%98%EC%84%B1-Object-Type-Compatibility#entry537comment</comments>
      <pubDate>Wed, 17 Dec 2025 15:57:39 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScirpt] 타입 계층도와 함께 기본타입 살펴보기</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScirpt-%ED%83%80%EC%9E%85-%EA%B3%84%EC%B8%B5%EB%8F%84%EC%99%80-%ED%95%A8%EA%BB%98-%EA%B8%B0%EB%B3%B8%ED%83%80%EC%9E%85-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트의 모든 타입은 집합의 포함 관계(계층)를 가진다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이 계층 구조를 이해하면 unknown, never, void, any의 동작 방식을 논리적으로 파악할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFEZHB%2FdJMcahpqHqP%2FnwRPreXKydmQhgXclLAUNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;443&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. Unknown 타입 (전체 집합)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;unknown은 타입 계층도의 &lt;b&gt;최상단&lt;/b&gt;에 위치한다. 집합으로 비유하면 모든 타입을 포함하는 &lt;b&gt;전체 집합(Universal Set)&lt;/b&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;업캐스팅 (가능):&lt;/b&gt; 모든 타입은 전체 집합의 부분집합이므로, unknown 타입 변수에는 어떤 값이든 할당할 수 있다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;let a: unknown = 1;         // number -&amp;gt; unknown
let b: unknown = &quot;hello&quot;;   // string -&amp;gt; unknown
let c: unknown = () =&amp;gt; {};  // function -&amp;gt; unknown&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다운캐스팅 (불가):&lt;/b&gt; 전체 집합을 특정 부분집합(예: number)으로 취급할 수는 없다. 따라서 unknown 타입의 값은 (any를 제외한) 다른 타입의 변수에 할당할 수 없다.
&lt;div&gt;
&lt;pre class=&quot;ceylon&quot;&gt;&lt;code&gt;let unknownValue: unknown;
// let a: number = unknownValue; // ❌ Error
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFEZHB%2FdJMcahpqHqP%2FnwRPreXKydmQhgXclLAUNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;443&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. Never 타입 (공집합)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;never는 타입 계층도의 &lt;b&gt;최하단&lt;/b&gt;에 위치한다. 집합으로 비유하면&lt;u&gt; 아무것도 포함하지 않는&lt;/u&gt; &lt;b&gt;공집합(Empty Set)&lt;/b&gt;이다. =&amp;gt; 어떤 값도 저장되어선 안되는 변수에 활용하면 좋다!&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념:&lt;/b&gt; 값 자체가 존재할 수 없음을 의미하며, 주로 에러를 던지거나(throw) 무한 루프를 도는 함수의 반환 타입으로 사용된다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;function errorFunc(): never {
  throw new Error();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;업캐스팅 (가능):&lt;/b&gt; 공집합은 모든 집합의 부분집합이다. 따라서 never 타입은 모든 타입으로 할당 가능하다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;let neverVar: never;
let a: number = neverVar; // ✅ OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다운캐스팅 (불가):&lt;/b&gt; 그 어떤 값도 공집합에 포함될 수 없다. 따라서 never 변수에는 어떤 값도 할당할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFEZHB%2FdJMcahpqHqP%2FnwRPreXKydmQhgXclLAUNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;443&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size26&quot;&gt;3. Void 타입&lt;/h2&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;void는 undefined 타입의 &lt;b&gt;슈퍼타입(부모&lt;/b&gt;&amp;nbsp;&lt;b&gt;타입)&lt;/b&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; undefined는 void의 부분집합이므로, void 타입 함수에서 undefined를 반환하거나 return 문을 생략하는 것이 가능하다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;function noReturn(): void {
  return undefined; // ✅ OK (undefined -&amp;gt; void 업캐스팅)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;할당:&lt;/b&gt; void 타입 변수에는 undefined와 never만 할당할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FEZHB/dJMcahpqHqP/nwRPreXKydmQhgXclLAUNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFEZHB%2FdJMcahpqHqP%2FnwRPreXKydmQhgXclLAUNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;443&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;4. Any 타입 (계층 무시)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;any는 타입 계층 구조를 완전히 무시하는 &lt;b&gt;치트키(Exception)&lt;/b&gt;다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; 모든 타입의 슈퍼타입이 될 수도 있고, 서브타입이 될 수도 있다. 즉, 모든 타입으로 업캐스팅과 다운캐스팅이 자유롭게 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;⚠️ 주의:&lt;/b&gt; 이는 타입 시스템의 안정성을 무너뜨리므로, 꼭 필요한 경우가 아니라면 사용을 지양해야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;any도 never로 다운캐스팅 불가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1765630414244&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let anyValue: any;
let num: number = anyValue; // ✅ OK (any -&amp;gt; number 다운캐스팅)
anyValue = num;             // ✅ OK (number -&amp;gt; any 업캐스팅)
neverVar = anyVar;			// ❌ any -&amp;gt; never 불가능&lt;/code&gt;&lt;/pre&gt;</description>
      <category>  TypeScript</category>
      <category>Any</category>
      <category>Never</category>
      <category>typescript</category>
      <category>Unknown</category>
      <category>void</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/536</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScirpt-%ED%83%80%EC%9E%85-%EA%B3%84%EC%B8%B5%EB%8F%84%EC%99%80-%ED%95%A8%EA%BB%98-%EA%B8%B0%EB%B3%B8%ED%83%80%EC%9E%85-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0#entry536comment</comments>
      <pubDate>Sat, 13 Dec 2025 21:54:55 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입은 집합이다(업캐스팅, 다운캐스팅)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%9D%80-%EC%A7%91%ED%95%A9%EC%9D%B4%EB%8B%A4%EC%97%85%EC%BA%90%EC%8A%A4%ED%8C%85-%EB%8B%A4%EC%9A%B4%EC%BA%90%EC%8A%A4%ED%8C%85</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caIw0F/dJMcajtW4MJ/mdrOY07eMaCPhbpBViw490/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caIw0F/dJMcajtW4MJ/mdrOY07eMaCPhbpBViw490/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caIw0F/dJMcajtW4MJ/mdrOY07eMaCPhbpBViw490/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaIw0F%2FdJMcajtW4MJ%2FmdrOY07eMaCPhbpBViw490%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;443&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blqXrM/dJMcadmXI1g/SYYdz9Lak3eR5E71mkr791/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blqXrM/dJMcadmXI1g/SYYdz9Lak3eR5E71mkr791/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blqXrM/dJMcadmXI1g/SYYdz9Lak3eR5E71mkr791/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblqXrM%2FdJMcadmXI1g%2FSYYdz9Lak3eR5E71mkr791%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트의 '타입'을 이해하는 가장 쉬운 방법은 이를 &lt;b&gt;여러개의값을포함하는집합(Set)&lt;/b&gt;으로 바라보는 것이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;집합은 동일한 속성을 갖는 여러 요소를 하나의 그룹으로 묶은 단위다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. 슈퍼타입과 서브타입&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집합의 포함 관계를 통해 타입 간의 부모-자식 관계를 정의할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMmdta/dJMcajgpSzc/KvmQM8VAG0YK5Po6G2SH11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMmdta/dJMcajgpSzc/KvmQM8VAG0YK5Po6G2SH11/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMmdta/dJMcajgpSzc/KvmQM8VAG0YK5Po6G2SH11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMmdta%2FdJMcajgpSzc%2FKvmQM8VAG0YK5Po6G2SH11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HjPYw/dJMcafd4unM/olpTSJ3dAuexRgKm0MEjC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HjPYw/dJMcafd4unM/olpTSJ3dAuexRgKm0MEjC1/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HjPYw/dJMcafd4unM/olpTSJ3dAuexRgKm0MEjC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHjPYw%2FdJMcafd4unM%2FolpTSJ3dAuexRgKm0MEjC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;슈퍼타입 (Super Type / 부모 타입):&lt;/b&gt; 다른 타입을 포함하는 거대한 집합이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: number 타입 (모든 숫자의 집합)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서브타입 (Sub Type / 자식 타입):&lt;/b&gt; 슈퍼타입에 포함되는 부분 집합이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: number literal 타입 (특정 숫자 하나만 포함하는 집합, 예: 20)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/skeGT/dJMcagD3SDD/GTkKIIeLnU38fzLEilGrE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/skeGT/dJMcagD3SDD/GTkKIIeLnU38fzLEilGrE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/skeGT/dJMcagD3SDD/GTkKIIeLnU38fzLEilGrE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FskeGT%2FdJMcagD3SDD%2FGTkKIIeLnU38fzLEilGrE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;숫자 20은 '20이라는 리터럴 타입'에 속하지만, 동시에 '숫자(Number) 타입'이라는 더 큰 집합에도 속한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;&lt;u&gt;모든 Number Literal 타입은 Number 타입의 부분 집합(서브타입)이다.&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;타입 호환성 (Type Compatibility)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cP4uN1/dJMcadAu5jp/0sKxuXF9qdKEFaS7KKnUuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cP4uN1/dJMcadAu5jp/0sKxuXF9qdKEFaS7KKnUuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cP4uN1/dJMcadAu5jp/0sKxuXF9qdKEFaS7KKnUuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcP4uN1%2FdJMcadAu5jp%2F0sKxuXF9qdKEFaS7KKnUuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입 호환성&lt;/b&gt;이란, &lt;b&gt;&quot;A 타입의 값을 B 타입으로 취급해도 되는가?&quot;&lt;/b&gt;를 판단하는 기준이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;이를 집합의 관계로 설명하면 다음과 같다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgCsmB/dJMcajgpSHx/LFEfad0zPkXKLeMIKFXjS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgCsmB/dJMcajgpSHx/LFEfad0zPkXKLeMIKFXjS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgCsmB/dJMcajgpSHx/LFEfad0zPkXKLeMIKFXjS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgCsmB%2FdJMcajgpSHx%2FLFEfad0zPkXKLeMIKFXjS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;1. 업캐스팅 (Upcasting)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;서브타입의 값을 슈퍼타입의 값으로 취급하는 것이다. 이는 &lt;b&gt;항상 허용&lt;/b&gt;된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비유:&lt;/b&gt; &quot;정사각형은 직사각형이다&quot;라는 명제는 참이다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;let num1: number = 10;
let num2: 10 = 10;

// ✅ OK: 10(서브타입)은 number(슈퍼타입)에 포함되므로 호환된다.
num1 = num2; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;2. 다운캐스팅 (Downcasting)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;슈퍼타입의 값을 서브타입의 값으로 취급하는 것이다. 이는 &lt;b&gt;대부분 허용되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비유:&lt;/b&gt; &quot;직사각형은 정사각형이다&quot;라는 명제는 거짓일 수 있다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;let num1: number = 10;
let num2: 10 = 10;

// ❌ Error: number(슈퍼타입)는 10 외에도 다른 수(999 등)를 가질 수 있어 호환되지 않는다.
num2 = num1; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 다운캐스팅은 불가능한가?&lt;/b&gt; num1(number 타입)에는 10뿐만 아니라 999, -50 등 다양한 숫자가 들어갈 수 있다. 하지만 num2(10 리터럴 타입)는 오직 10만 담을 수 있는 작은 그릇이다. 더 큰 집합의 요소를 작은 부분 집합에 강제로 넣으려 하면 데이터의 무결성이 깨질 위험이 크기 때문에 타입스크립트는 이를 막는다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nYu96/dJMcahiEqpU/IHJp3jg1XSb2KJhzwVs7yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nYu96/dJMcahiEqpU/IHJp3jg1XSb2KJhzwVs7yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nYu96/dJMcahiEqpU/IHJp3jg1XSb2KJhzwVs7yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnYu96%2FdJMcahiEqpU%2FIHJp3jg1XSb2KJhzwVs7yk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size26&quot;&gt;  요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입스크립트의 타입 관계는 &lt;b&gt;집합의 포함 관계&lt;/b&gt;와 같다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;업캐스팅(서브 &amp;rarr; 슈퍼):&lt;/b&gt; 안전하며 항상 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다운캐스팅(슈퍼 &amp;rarr; 서브):&lt;/b&gt; 위험하며 대부분 불가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQogqL/dJMcadgcrKn/983ecFTkOtYD1iKCbnnnuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQogqL/dJMcadgcrKn/983ecFTkOtYD1iKCbnnnuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQogqL/dJMcadgcrKn/983ecFTkOtYD1iKCbnnnuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQogqL%2FdJMcadgcrKn%2F983ecFTkOtYD1iKCbnnnuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;908&quot; height=&quot;438&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>다운케스팅</category>
      <category>업케스팅</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/535</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%9D%80-%EC%A7%91%ED%95%A9%EC%9D%B4%EB%8B%A4%EC%97%85%EC%BA%90%EC%8A%A4%ED%8C%85-%EB%8B%A4%EC%9A%B4%EC%BA%90%EC%8A%A4%ED%8C%85#entry535comment</comments>
      <pubDate>Sat, 13 Dec 2025 20:55:50 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] Void와 Never 타입</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-Void%EC%99%80-Never-%ED%83%80%EC%9E%85</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 '값을 반환하지 않음'을 나타내는 두 가지 특수 타입, void와 never에 대해 알아본다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;두 타입은 비슷해 보이지만, &lt;b&gt;&quot;종료가 되느냐, 안 되느냐&quot;&lt;/b&gt;에 따라 명확한 차이가 있다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. Void 타입&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;void는 &lt;b&gt;&quot;아무런 값도 없음&quot;&lt;/b&gt;을 의미하는 타입이다. 주로 값을 반환하지 않는 함수의 반환 타입으로 사용된다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;1.1. 함수에서의 사용&lt;/h3&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;함수가 명시적인 return 문을 가지지 않거나, return;으로 종료될 때 사용한다. 실제로 자바스크립트 함수는 반환값이 없으면 암묵적으로 undefined를 반환하지만, &lt;u&gt;타입스크립트에서 &quot;&lt;b&gt;이 함수의 반환값은 사용하지 않는다&lt;/b&gt;&quot;는 의도를 표현할 때 void를 쓴다.&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiDz9jfkLqRAxUAAAAAHQAAAAAQrwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;function func2(): void {
  console.log(&quot;hello&quot;);
  // 명시적인 return이 없으므로 실제로는 undefined가 반환되지만,
  // 타입스크립트는 이를 '반환값이 없음(void)'으로 간주한다.
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;1.2. 변수에서의 사용&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;변수에도 void 타입을 지정할 수 있지만, 실무에서는 거의 사용하지 않는다. void 타입 변수에는 오직 undefined만 할당할 수 있기 때문이다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiDz9jfkLqRAxUAAAAAHQAAAAAQsAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let a: void;
a = undefined; // ✅ OK
// a = null;   // ❌ Error (strictNullChecks: true 기준)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;12&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;12,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고:&lt;/b&gt; tsconfig.json에서 strictNullChecks: false로 설정하면 null도 할당할 수 있지만, 엄격한 타입 검사를 위해 권장하지 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;2. Never 타입&lt;/h2&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;never는 &lt;b&gt;&quot;절대 발생할 수 없는 값&quot;&lt;/b&gt; 또는 &lt;b&gt;&quot;불가능&quot;&lt;/b&gt;을 의미하는 타입이다. 수학적으로는 공집합(Empty Set)과 같다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;2.1. 함수에서의 사용&lt;/h3&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;함수가 &lt;b&gt;정상적으로 종료되지 않아&lt;/b&gt; 반환값 자체가 존재할 수 없는 경우에 사용한다. 대표적으로 두 가지 케이스가 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Case 1: 무한 루프&lt;/b&gt; 함수가 끝나지 않고 영원히 실행되는 경우다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiDz9jfkLqRAxUAAAAAHQAAAAAQsQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;function func3(): never {
  while (true) {
    // 영원히 반복되므로 함수가 종료될 수 없음
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Case 2: 에러 발생 (Throw)&lt;/b&gt; 함수 실행 중 에러를 던져서 강제로 프로그램이 중단되거나 catch 블록으로 넘어가는 경우다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiDz9jfkLqRAxUAAAAAHQAAAAAQsgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;function func4(): never {
  throw new Error(); // 에러 발생 시점에서 실행 중단
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;2.2. 변수에서의 사용 (특징)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;never 타입은 &lt;b&gt;가장 좁은 타입&lt;/b&gt;이다. 즉, never 타입 변수에는 &lt;b&gt;그 어떤 값도(심지어 any 타입 값조차) 할당할 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiDz9jfkLqRAxUAAAAAHQAAAAAQswE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;let anyVar: any = 10;
let a: never;

// ❌ 모든 할당이 불가능함
// a = 1;
// a = null;
// a = undefined;
// a = anyVar; // any도 할당 불가
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;이러한 특징 때문에 &lt;u&gt;never&lt;/u&gt;는 이후 배울 '타입 좁히기'에서 &lt;u&gt;&quot;절대 도달할 수 없는 코드(Dead Code)&quot;&lt;/u&gt;를 검증하는 데 유용하게 사용된다.&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>Never</category>
      <category>typescript</category>
      <category>void</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/534</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-Void%EC%99%80-Never-%ED%83%80%EC%9E%85#entry534comment</comments>
      <pubDate>Sat, 13 Dec 2025 20:22:53 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] Any와 Unknown 타입</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-Any%EC%99%80-Unknown-%ED%83%80%EC%9E%85</link>
      <description>&lt;h2 data-path-to-node=&quot;2&quot; data-ke-size=&quot;size26&quot;&gt;Any와 Unknown 타입&lt;/h2&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 모든 변수의 타입을 엄격하게 관리하지만,&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;개발 과정에서 불가피하게 타입을 알 수 없거나 유연한 처리가 필요한 상황이 발생한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;이때 사용하는 것이 &lt;b&gt;any&lt;/b&gt;와 &lt;b&gt;unknown&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;Any 타입&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;any는 타입스크립트의 모든 타입 검사를 무력화하는 &lt;b&gt;치트키(Cheat Key)&lt;/b&gt; 같은 타입이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;u&gt;특정 변수의 타입을 우리가 확실히 모를때 사용한다. (any: 어떤 타입이든지 가능!)&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모든 값 허용:&lt;/b&gt; 숫자, 문자열, 불리언 등 어떤 타입의 값이라도 할당할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 연산 허용:&lt;/b&gt; 타입 검사를 받지 않으므로, 메서드 호출이나 연산 등 모든 동작이 허용된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 곳에 할당 가능:&lt;/b&gt; any 타입의 값은 다른 어떤 타입의 변수에도 할당할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQzAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let anyVar: any = 10;
anyVar = &quot;hello&quot;;   // ✅ OK: 타입 변경 가능
anyVar = true;      // ✅ OK: 타입 변경 가능

anyVar.toUpperCase(); // ✅ OK: 컴파일 에러 없음
anyVar.toFixed();     // ✅ OK: 컴파일 에러 없음

let num: number = 10;
num = anyVar;         // ✅ OK: 모든 타입 변수에 할당 가능
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⚠️ 위험성&lt;/b&gt; any는 컴파일 단계에서 에러를 잡지 않으므로, 실행 시점(Runtime)에 치명적인 오류를 발생시킬 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;위 코드에서 anyVar가 true일 때 toUpperCase()를 호출하면 런타임 에러가 발생하여 프로그램이 종료된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt; &lt;u&gt;&amp;nbsp;&lt;b&gt;any는 타입스크립트의 사용 이점을 없애버리므로, 불가피한 경우가 아니면 사용을 지양해야 한다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size26&quot;&gt;Unknown 타입&lt;/h2&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;unknown은 any와 비슷하게 모든 값을 저장할 수 있지만, &lt;b&gt;사용은 엄격하게 제한&lt;/b&gt;되는 보다 안전한 타입이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모든 값 허용:&lt;/b&gt; any처럼 어떤 타입의 값이라도 할당할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 제한 (중요):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;unknown 타입의 값은 any나 unknown 타입을 제외한 &lt;b&gt;다른 변수에 할당할 수 없다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;프로퍼티 접근, 메서드 호출, 연산 등이 &lt;b&gt;불가능하다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQzQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;let unknownVar: unknown;

// 값을 넣는 것은 자유로움
unknownVar = &quot;&quot;;
unknownVar = 1;
unknownVar = () =&amp;gt; {};

// ❌ Error: 다른 타입의 변수에 할당 불가
let num: number = 10;
// num = unknownVar; 

// ❌ Error: 연산 및 메서드 호출 불가
// unknownVar * 2;
// unknownVar.toUpperCase();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  올바른 사용법: 타입 좁히기 (Type Narrowing)&lt;/b&gt; unknown 타입의 값을 실제로 사용하려면, 조건문을 통해 현재 값이 어떤 타입인지 확인하는 과정을 거쳐야 한다. 이를 &lt;b&gt;타입 좁히기&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQzgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;if (typeof unknownVar === &quot;number&quot;) {
  // 이 블록 안에서는 unknownVar가 number 타입으로 간주됨
  console.log(unknownVar * 2); // ✅ OK
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;변수의 타입을 미리 알 수 없는 상황이라면,&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;무조건적인 자유를 주는 any보다는 값을 할당할 수는 있되 사용에는 제약을 두는 &lt;b&gt;unknown을 사용하는 것이 훨씬 안전하다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>Any</category>
      <category>typescript</category>
      <category>Unknown</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/532</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-Any%EC%99%80-Unknown-%ED%83%80%EC%9E%85#entry532comment</comments>
      <pubDate>Thu, 11 Dec 2025 15:55:26 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 열거형 타입 (Enum Type)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%97%B4%EA%B1%B0%ED%98%95-%ED%83%80%EC%9E%85-Enum-Type</link>
      <description>&lt;h2 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;열거형(Enum)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에는 없는 &lt;u&gt;타입스크립트만의 고유 기능&lt;/u&gt;으로,&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러가지 값들에 각각 이름을 부여해 열거해두고 사용하는 타입&lt;/b&gt;이다. 또한 &lt;b&gt;연관된 상수들의 집합&lt;/b&gt;을 정의할 때 사용한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;의미 있는 이름을 부여하여 코드의 가독성을 높이고, 오타 등의 실수를 방지할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;숫자형 Enum (Numeric Enum)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;Enum의 각 멤버에 정수 값을 할당하는 가장 기본적인 형태다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;자동 할당&lt;/h3&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;별도의 값을 지정하지 않으면 첫 번째 멤버에 0이 할당되고, 이후 멤버들은 &lt;b&gt;1씩 자동으로 증가&lt;/b&gt;한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQtgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum Role {
  ADMIN, // 0 (자동 할당)
  USER,  // 1 (자동 할당)
  GUEST  // 2 (자동 할당)
}

const user1 = {
  name: &quot;이정환&quot;,
  role: Role.ADMIN, // 실제 값: 0
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;수동 할당 (초기화)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;특정 멤버의 값을 지정하면, 그 다음 멤버부터는 지정된 값에서 1씩 증가한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQtwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum Role {
  ADMIN = 10, // 10으로 지정
  USER,       // 11 (자동 할당)
  GUEST       // 12 (자동 할당)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;문자열 Enum (String Enum)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;멤버에 의미 있는 문자열 값을 직접 할당할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;숫자형과 달리 값이 자동으로 증가하지 않으므로 모든 멤버의 값을 명시적으로 초기화해야 한다.&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQuAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum Language {
  korean = &quot;ko&quot;,
  english = &quot;en&quot;,
}

const user1 = {
  name: &quot;이정환&quot;,
  language: Language.korean, // &quot;ko&quot;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt; 문자열 값을 직접 입력(&quot;ko&quot;)하는 대신 Enum 멤버(Language.korean)를 사용하므로, &quot;kos&quot;, &quot;KO-kr&quot;과 같은 &lt;b&gt;오타로 인한 버그를 원천적으로 방지&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size26&quot;&gt;Enum의 컴파일 특징&lt;/h2&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;대부분의 타입스크립트 문법(Type Alias, Interface 등)은 컴파일 시 제거되지만,&lt;/p&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Enum은 컴파일 후에도 자바스크립트 객체로 변환되어 코드에 남는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 런타임(프로그램 실행 중)에도 실제 값으로 사용할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입스크립트 코드&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQuQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum Role {
  ADMIN,
  USER,
  GUEST,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컴파일된 자바스크립트 코드 (결과)&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQugE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;var Role;
(function (Role) {
    Role[Role[&quot;ADMIN&quot;] = 0] = &quot;ADMIN&quot;;
    Role[Role[&quot;USER&quot;] = 1] = &quot;USER&quot;;
    Role[Role[&quot;GUEST&quot;] = 2] = &quot;GUEST&quot;;
})(Role || (Role = {}));
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 객체 형태로 변환되므로 Role.ADMIN과 같이 값에 접근하여 사용할 수 있는 것이다.&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>enum</category>
      <category>typescirpt</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/531</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%97%B4%EA%B1%B0%ED%98%95-%ED%83%80%EC%9E%85-Enum-Type#entry531comment</comments>
      <pubDate>Thu, 11 Dec 2025 15:43:14 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입 별칭 (Type Alias)과 인덱스 시그니쳐 (Index Signature)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EB%B3%84%EC%B9%AD-Type-Alias%EA%B3%BC-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B3%90-Index-Signature</link>
      <description>&lt;h2 data-path-to-node=&quot;2&quot; data-ke-size=&quot;size26&quot;&gt;타입 별칭 (Type Alias)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입 별칭은 변수를 선언하듯 &lt;b&gt;타입에 이름을 붙여 별도로 정의하는 문법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;복잡한 타입을 매번 작성할 필요 없이, 이름을 통해 쉽게 재사용할 수 있어 코드의 가독성과 유지보수성이 높아진다.  &lt;/u&gt;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;정의 및 사용법&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;type 키워드를 사용해 정의한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQiwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;// 타입 별칭 정의
type User = {
  id: number;
  name: string;
  nickname: string;
  birth: string;
  bio: string;
  location: string;
};

// 타입 별칭 사용
let user1: User = {
  id: 1,
  name: &quot;이정환&quot;,
  nickname: &quot;winterlood&quot;,
  birth: &quot;1997.01.07&quot;,
  bio: &quot;안녕하세요&quot;,
  location: &quot;부천시&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;스코프(Scope) 규칙&lt;/span&gt;:&lt;/b&gt; 변수와 마찬가지로, &lt;b&gt;동일한 스코프 내에서는 같은 이름의 타입 별칭을 중복 선언할 수 없다.&lt;/b&gt; &lt;u&gt;단, 스코프가 다르다면(함수 내부 등) 동일한 이름을 사용할 수 있다.&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;컴파일 결과&lt;/span&gt;:&lt;/b&gt; 타입 별칭은 타입스크립트 고유의 문법이므로, &lt;b&gt;컴파일 시 완전히 제거된다.&lt;/b&gt; 생성된 자바스크립트 파일에는 타입 정의가 남지 않으며, 객체 리터럴 값만 남는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;인덱스 시그니처 (Index Signature)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;인덱스 시그니처는 &lt;b&gt;객체의 프로퍼티 이름(Key)을 미리 알 수 없거나, 프로퍼티의 개수가 가변적일 때&lt;/b&gt; 타입을 유연하게 정의하는 문법이다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;사용 배경&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;수많은 국가 코드를 저장하는 객체가 있다고 가정하면 모든 국가의 코드를 일일이 타입으로 정의하는 것은 비효율적이다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQjAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;elm&quot;&gt;&lt;code&gt;// ❌ 비효율적인 방식: 모든 프로퍼티를 직접 명시해야 함
type CountryCodes = {
  Korea: string;
  UnitedState: string;
  UnitedKingdom: string;
  // ... (수백 개의 국가를 일일이 나열해야 함)
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;문법 및 적용&lt;/h3&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;인덱스 시그니처를 사용하면 &quot;Key와 Value의 타입 규칙&quot;만 정의하여 이를 해결할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQjQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// ✅ 인덱스 시그니처 사용
type CountryCodes = {
  [key: string]: string;
};

let countryCodes: CountryCodes = {
  Korea: &quot;ko&quot;,
  UnitedState: &quot;us&quot;,
  Brazil: &quot;bz&quot;, // 자유롭게 추가 가능
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[key: string]: 객체의 Key(프로퍼티 명)는 문자열 타입이다.&lt;/li&gt;
&lt;li&gt;: string: 해당 Key에 매핑되는 Value는 문자열 타입이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;주의사항: 타입 호환성&lt;/h3&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;인덱스 시그니처와 함께 &lt;b&gt;반드시 포함해야 할 구체적인 프로퍼티&lt;/b&gt;를 명시할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;단, 이때 명시된 프로퍼티의 값 타입은 &lt;b&gt;반드시 인덱스 시그니처의 값 타입과 일치하거나 호환&lt;/b&gt;되어야 한다.&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjty7m06LSRAxUAAAAAHQAAAAAQjgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;type CountryNumberCodes = {
  [key: string]: number; // 모든 Value는 number여야 함
  Korea: number;         // ✅ OK: number 타입이므로 호환됨
  // UnitedState: string; // ❌ Error: string은 number에 할당할 수 없음
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;인덱스 시그니처가 &quot;모든 속성의 값은 숫자여야 한다&quot;라고 선언했기 때문에, 예외적으로 문자열을 갖는 속성을 추가할 수 없다.&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>인덱스 시그니처</category>
      <category>타입 별칭</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/530</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85-%EB%B3%84%EC%B9%AD-Type-Alias%EA%B3%BC-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B3%90-Index-Signature#entry530comment</comments>
      <pubDate>Thu, 11 Dec 2025 15:25:28 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 객체(Object)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EA%B0%9D%EC%B2%B4Object</link>
      <description>&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;object 타입의 한계&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;object&lt;/b&gt;는 단순히 해당 변수가 &quot;&lt;b&gt;객체임&lt;/b&gt;&quot;을 명시하는 타입이다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjty7m06LSRAxUAAAAAHQAAAAAQbA&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;let user: object = {
  id: 1,
  name: &quot;이정환&quot;,
};

// ❌ Error: 'object' 형식에 'id' 속성이 없습니다.
// user.id;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;위 코드에서 user는 객체로 잘 정의되었지만, &lt;i&gt;user.id에 접근하려 하면 에러가 발생한다. &lt;/i&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr;&amp;nbsp;object 타입이 객체의 내부 구조(프로퍼티 정보)에 대한 정보는 전혀 가지고 있지 않기 때문이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;따라서 실무에서는 거의 사용되지 않는다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;객체 리터럴 타입 (Object Literal Type)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;객체의 구조를 정확히 반영하기 위해서는 &lt;b&gt;객체 리터럴 타입&lt;/b&gt;을 사용해야 한다. &lt;u&gt;중괄호 {}를 열고 객체가 가진 프로퍼티와 그 타입을 직접 나열하는 방식&lt;/u&gt;이다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjty7m06LSRAxUAAAAAHQAAAAAQbQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let user: {
  id: number;
  name: string;
} = {
  id: 1,
  name: &quot;이정환&quot;,
};

// ✅ OK: 정상적으로 접근 가능
user.id;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 정의하면 타입스크립트가 객체의 내부 구조를 파악할 수 있어, 점 표기법 등을 통해 프로퍼티에 안전하게 접근할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;구조적 타입 시스템 ( Property Type System)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 C나 Java 같은 명목적 타입 시스템(Nominal Type System)과 달리, &lt;b&gt;프로퍼티를 기준으로 타입을 정의&lt;/b&gt;한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjty7m06LSRAxUAAAAAHQAAAAAQbg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;let dog: {
  name: string;
  color: string;
} = {
  name: &quot;돌돌이&quot;,
  color: &quot;brown&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 &quot;이름이 무엇인가&quot;가 아니라 &quot;&lt;b&gt;어떤 구조(프로퍼티)를 가지고 있는가&lt;/b&gt;&quot;를 기준으로 타입을 판단한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;이를 &lt;b&gt;구조적 타입 시스템(PropertyType System)&lt;/b&gt;이라고 부른다. (구조를 기준으로 타입을 정한다는 의미!)&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;즉, name과 color라는 프로퍼티가 있다면 그 구조에 맞춰 타입을 인정해 주는 방식이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;larr;&amp;rarr; 명목적 타입 시스템: 이름 선언해서 만드는 방식&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size26&quot;&gt;객체 타입의 특수 기능&lt;/h2&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;객체 타입을 정의할 때, 특정 프로퍼티를 상황에 따라 생략하거나 수정하지 못하게 막아야 할 때가 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;이때 사용하는 것이 &lt;b&gt;선택적 프로퍼티&lt;/b&gt;와 &lt;b&gt;읽기 전용 프로퍼티&lt;/b&gt;다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;선택적 프로퍼티 (Optional Property)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;특정 프로퍼티가 있어도 되고 없어도 되는 경우&lt;/u&gt;, 프로퍼티 이름 뒤에 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;물음표(?)&lt;/b&gt;&lt;/span&gt;를 붙여 정의한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjty7m06LSRAxUAAAAAHQAAAAAQbw&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let user: {
  id?: number; // 선택적 프로퍼티: id는 없어도 됨
  name: string;
} = {
  id: 1,
  name: &quot;이정환&quot;,
};

// ✅ OK: id가 없어도 에러가 발생하지 않음
user = {
  name: &quot;홍길동&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;단, 해당 프로퍼티가 존재한다면 반드시 정의된 타입(여기서는 number)을 따라야 한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;읽기 전용 프로퍼티 (Readonly Property)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;특정 프로퍼티 값을 초기화한 이후에 변경하지 못하게 하려면&lt;/u&gt; &lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;readonly&lt;/span&gt; &lt;/b&gt;키워드를 사용한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwjty7m06LSRAxUAAAAAHQAAAAAQcA&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let user: {
  id?: number;
  readonly name: string; // 읽기 전용 설정
} = {
  id: 1,
  name: &quot;이정환&quot;,
};

// ❌ Error: 읽기 전용 속성이므로 값을 할당할 수 없습니다.
// user.name = &quot;수정불가&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 API Key나 고유 ID처럼 변하면 안 되는 중요한 데이터가 의도치 않게 수정되는 것을 방지할 수 있다.&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>객체</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/529</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EA%B0%9D%EC%B2%B4Object#entry529comment</comments>
      <pubDate>Thu, 11 Dec 2025 14:49:41 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 배열(Array)과 튜플(Tuple)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EB%B0%B0%EC%97%B4Array%EA%B3%BC-%ED%8A%9C%ED%94%8CTuple</link>
      <description>&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQhAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #000000; font-size: 1.44em; letter-spacing: -1px;&quot;&gt;배열 (Array)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트에서 배열을 정의하는 방법은 두 가지가 있다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;방법1: 기본 정의 방법 (type[]) &amp;rarr;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;가장 일반적으로 사용하는 방식이다.&lt;u&gt; 자료형 뒤에 대괄호([])를 붙여 선언&lt;/u&gt;한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQhQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 숫자 배열
let numArr: number[] = [1, 2, 3];

// 문자열 배열
let strArr: string[] = [&quot;hello&quot;, &quot;im&quot;, &quot;winterlood&quot;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;방법2: 제네릭 문법 사용 (Array&amp;lt;type&amp;gt;)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;Array&amp;lt;타입&amp;gt; 형태의 제네릭 문법을 사용&lt;/u&gt;할 수도 있다. 기능은 위와 완전히 동일하다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQhgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;let boolArr: Array&amp;lt;boolean&amp;gt; = [true, false, true];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;유니온 타입 배열 (다양한 타입 혼합)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;배열에 여러 타입의 요소를 함께 저장&lt;/u&gt;하고 싶다면 &lt;b&gt;유니온 타입(|)&lt;/b&gt;을 사용한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQhwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;// number 또는 string 타입의 요소만 허용
let multiArr: (number | string)[] = [1, &quot;hello&quot;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;다차원 배열&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;대괄호를 연달아 작성하여&lt;u&gt; 2차원 이상의 배열을 정의&lt;/u&gt;할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQiAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;let doubleArr: number[][] = [
  [1, 2, 3],
  [4, 5],
];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size26&quot;&gt;튜플 (Tuple)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;튜플은 자바스크립트에는 없는 타입스크립트만의 특수 타입으로, &lt;u&gt;&lt;b&gt;길이와 각 요소의 타입이 고정된 배열&lt;/b&gt;&lt;/u&gt;을 의미한다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size23&quot;&gt;튜플 정의&lt;/h3&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;대괄호 안에 각 요소의 타입을 순서대로 명시한다. &lt;u&gt;정의된 길이와 순서를 반드시 지켜야 한다 ⭐&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQiQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;// 길이가 2이고, 순서대로 number, number 타입을 갖는 튜플
let tup1: [number, number] = [1, 2];

// 길이가 3이고, 순서대로 number, string, boolean 타입을 갖는 튜플
let tup2: [number, string, boolean] = [1, &quot;hello&quot;, true];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size23&quot;&gt;튜플의 한계 (주의사항)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;튜플은 컴파일 시 일반적인 자바스크립트 배열로 변환된다. 따라서 배열 메서드인 push나 pop을 사용하면 &lt;b&gt;고정된 길이를 무시하고 요소를 추가/삭제할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQigE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let tup1: [number, number] = [1, 2];

// ⚠️ 에러가 발생하지 않음 (튜플의 제약이 깨짐)
tup1.push(1);
tup1.push(1);
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;30&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;30,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의:&lt;/b&gt; 튜플을 사용할 때는 push, pop 등의 메서드 사용을 자제하여 타입 안전성을 스스로 지켜야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;튜플의 활용 사례&lt;/h3&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;튜플은 데이터의 순서와 양이 중요한 경우 유용하다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 사용자 정보를 [이름, 아이디] 순서로 저장하는 배열이 있다고 가정해 보자!&lt;/p&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;33&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반 배열 사용 시 (문제점)&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQiwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;// 순서가 바뀌거나, 엉뚱한 타입이 추가되어도 에러를 잡지 못함
const users = [
  [&quot;이정환&quot;, 1],
  [5, &quot;조아무개&quot;], // 의도와 다르게 [아이디, 이름] 순서로 저장됨
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;35&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;튜플 사용 시 (해결책)&lt;/b&gt; 튜플을 사용하면 데이터의 순서와 타입이 맞지 않을 경우 즉시 에러를 발생시킨다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjKpf6wlLORAxUAAAAAHQAAAAAQjAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;const users: [string, number][] = [
  [&quot;이정환&quot;, 1],
  [&quot;이아무개&quot;, 2],
  [5, &quot;조아무개&quot;], // ❌ Error: 첫 번째 요소는 string이어야 합니다.
];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>배열</category>
      <category>배열타입</category>
      <category>타입</category>
      <category>타입스크립트</category>
      <category>튜플</category>
      <category>튜플타입</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/528</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EB%B0%B0%EC%97%B4Array%EA%B3%BC-%ED%8A%9C%ED%94%8CTuple#entry528comment</comments>
      <pubDate>Wed, 10 Dec 2025 23:13:45 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 원시타입과 리터럴 타입</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9B%90%EC%8B%9C%ED%83%80%EC%9E%85%EA%B3%BC-%EB%A6%AC%ED%84%B0%EB%9F%B4-%ED%83%80%EC%9E%85</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;원시 타입(Primitive Type)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1869&quot; data-origin-height=&quot;755&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7ovKK/dJMcaioiHZ8/9krTofq2ArCL58T85OO7Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7ovKK/dJMcaioiHZ8/9krTofq2ArCL58T85OO7Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7ovKK/dJMcaioiHZ8/9krTofq2ArCL58T85OO7Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7ovKK%2FdJMcaioiHZ8%2F9krTofq2ArCL58T85OO7Ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1869&quot; height=&quot;755&quot; data-origin-width=&quot;1869&quot; data-origin-height=&quot;755&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;동시에 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;하나의 값만&lt;/span&gt;&lt;/b&gt; 저장할 수 있는 가장 기본적인 타입&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;배열이나 객체 같은 비원시 타입과 달리, number, string처럼 구체적인 데이터 하나만을 다룬다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;변수명 뒤에 : 타입을 명시하여 변수의 타입을 지정하는 문법을 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;타입 주석(Type Annotation)&lt;/b&gt;&lt;/span&gt;이라고 한다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;주요 원시 타입&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;number (숫자)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;자바스크립트의 모든 숫자값을 포함한다&lt;/u&gt;. 정수뿐만 아니라 소수, 음수, 무한대(Infinity), 숫자가 아님(NaN)도 포함된다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEqaun27KRAxUAAAAAHQAAAAAQuQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;let num1: number = 123;
let num2: number = -123;
let num3: number = 0.123;
let num4: number = -Infinity;
let num5: number = NaN;

// ❌ Error: 숫자 타입에는 문자열 메서드 사용 불가
// num1.toUpperCase();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;string (문자열)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;큰따옴표(&quot;), 작은따옴표('), 백틱(`)으로 감싼 모든 문자열을 포함&lt;/u&gt;한다.&lt;u&gt; 템플릿 리터럴 문법도 사용 가능&lt;/u&gt;하다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEqaun27KRAxUAAAAAHQAAAAAQugE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;let str1: string = &quot;hello&quot;;
let str2: string = 'hello';
let str3: string = `hello`;
let str4: string = `hello ${str1}`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;boolean (논리)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;오직&lt;/u&gt; 참(true)과 거짓(false) 두 가지 값만 저장한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEqaun27KRAxUAAAAAHQAAAAAQuwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let bool1: boolean = true;
let bool2: boolean = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;null / undefined&lt;/h3&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;각각 null과 undefined라는&lt;u&gt; 단일 값만을 포함&lt;/u&gt;하는 타입이다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEqaun27KRAxUAAAAAHQAAAAAQvAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let null1: null = null;
let unde1: undefined = undefined;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size26&quot;&gt;엄격한 null 검사 (strictNullChecks)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 변수를 초기화할 때 임시로 null을 넣는 경우가 많다. 하지만 &lt;u&gt;타입스크립트의 기본 설정(strict 모드)에서는 이를 허용하지 않는다.&lt;/u&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEqaun27KRAxUAAAAAHQAAAAAQvQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;// ❌ strict 모드에서는 number 타입에 null 할당 불가
let numA: number = null;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;옵션 설정 (tsconfig.json)&lt;/b&gt; null을 다른 타입의 변수에 할당하고 싶다면 &lt;b&gt;strictNullChecks&lt;/b&gt; 옵션을 조정해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;23&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;true (기본값/권장):&lt;/b&gt; null 타입을 제외한 변수에 null 할당을 금지한다. 안정성을 위해 켜두는 것이 좋다. (strict: true 설정 시 자동으로 켜짐)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;false:&lt;/b&gt; 모든 타입의 변수에 null을 할당할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEqaun27KRAxUAAAAAHQAAAAAQvgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;strictNullChecks&quot;: false
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size26&quot;&gt;리터럴 타입 (Literal Types)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트에서는 구체적인 &lt;u&gt;&lt;b&gt;값(Value)&lt;/b&gt; 자체를 타입으로 사용&lt;/u&gt;할 수 있다. 이를 &lt;u&gt;&lt;b&gt;리터럴 타입&lt;/b&gt;&lt;/u&gt;이라고 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;변수를 리터럴 타입으로 정의하면, 해당 변수에는 &lt;b&gt;지정된 그 값&lt;/b&gt; 외에는 저장할 수 없다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEqaun27KRAxUAAAAAHQAAAAAQvwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;// 숫자 리터럴 타입: 오직 10만 허용
let numA: 10 = 10;

// 문자열 리터럴 타입
let strA: &quot;hello&quot; = &quot;hello&quot;;

// 불리언 리터럴 타입
let boolA: true = true;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>리터럴타입</category>
      <category>원시타입</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/527</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9B%90%EC%8B%9C%ED%83%80%EC%9E%85%EA%B3%BC-%EB%A6%AC%ED%84%B0%EB%9F%B4-%ED%83%80%EC%9E%85#entry527comment</comments>
      <pubDate>Wed, 10 Dec 2025 22:47:05 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 기본 타입(Basic Types)과 실습 환경 설정</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EA%B8%B0%EB%B3%B8-%ED%83%80%EC%9E%85Basic-Types%EA%B3%BC-%EC%8B%A4%EC%8A%B5-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95</link>
      <description>&lt;h2 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;기본 타입(Basic Types)이란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tr3KH/dJMcaaKzMOg/if8bFj8L8Kl1loobzM636k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tr3KH/dJMcaaKzMOg/if8bFj8L8Kl1loobzM636k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tr3KH/dJMcaaKzMOg/if8bFj8L8Kl1loobzM636k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftr3KH%2FdJMcaaKzMOg%2Fif8bFj8L8Kl1loobzM636k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;기본 타입은 타입스크립트가 자체적으로 제공하는 &lt;b&gt;내장 타입(Built-in Types)&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;number, string처럼 자바스크립트와 공유하는 타입뿐만 아니라, any, void, never, unknown 등 타입스크립트만의 고유한 특수 타입도 포함된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입 계층도 (Type Hierarchy)&lt;/b&gt; 타입스크립트의 모든 기본 타입은 서로 부모-자식 관계를 이루며 하나의 거대한 계층 구조를 형성한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원시 타입 (Primitive Types):&lt;/b&gt; number, string, boolean 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비원시 타입 (Non-primitive Types):&lt;/b&gt; object, Array 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특수 타입:&lt;/b&gt; any, unknown, void, never 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;이후 학습 과정에서는&lt;span style=&quot;background-color: #f6e199;&quot;&gt; &lt;b&gt;[원시 타입 &amp;rarr; 비원시 타입 &amp;rarr; 특수 타입]&lt;/b&gt; &lt;/span&gt;순서로 각 타입의 특징과 활용법을 상세히 다룬다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;실습 환경 구성&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;프로젝트 초기화&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이전 섹션에서 만든 onebite-typescript 폴더 안에 &lt;b&gt;section2&lt;/b&gt; 폴더를 생성한다.&lt;/li&gt;
&lt;li&gt;VSCode에서 section2 폴더를 연 뒤, 터미널에서 패키지를 초기화한다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;npm init&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Node.js 내장 타입 정보를 제공하는 패키지를 설치한다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;npm i @types/node
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;컴파일러 옵션 설정 (tsconfig.json)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트 루트(section2)에 tsconfig.json 파일을 생성하고 아래 설정을 입력한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwiEqaun27KRAxUAAAAAHQAAAAAQfg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ESNext&quot;,           // 변환될 자바스크립트의 버전 (최신 버전 사용)
    &quot;module&quot;: &quot;ESNext&quot;,           // 변환될 모듈 시스템 (import/export 문법 사용)
    &quot;outDir&quot;: &quot;dist&quot;,             // 컴파일된 자바스크립트 파일이 저장될 폴더
    &quot;strict&quot;: true,               // 엄격한 타입 검사 모드 활성화 (권장)
    &quot;moduleDetection&quot;: &quot;force&quot;,   // 모든 파일을 독립 모듈로 취급 (전역 스코프 충돌 방지)
    &quot;skipLibCheck&quot;: true          // 외부 라이브러리 파일(.d.ts)의 타입 검사 생략 (속도 향상)
  },
  &quot;include&quot;: [&quot;src&quot;]              // 컴파일할 소스 코드가 위치한 폴더 범위 지정
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;모듈 시스템 설정 (package.json)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;tsconfig.json에서 module 옵션을 ESNext로 설정했으므로, Node.js가 이를 ES 모듈 시스템으로 인식하도록 설정해야 한다. package.json 파일을 열어 &quot;type&quot;: &quot;module&quot; 속성을 추가한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cav0Sg/dJMcacBDqf9/zJYCfgIyVAoBFmeLm1kez1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cav0Sg/dJMcacBDqf9/zJYCfgIyVAoBFmeLm1kez1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cav0Sg/dJMcacBDqf9/zJYCfgIyVAoBFmeLm1kez1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcav0Sg%2FdJMcacBDqf9%2FzJYCfgIyVAoBFmeLm1kez1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;338&quot; height=&quot;207&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwiEqaun27KRAxUAAAAAHQAAAAAQfw&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;{
  ...
  &quot;type&quot;: &quot;module&quot;,
  ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-size: 1.44em; letter-spacing: -1px;&quot;&gt;동작 확인&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;설정이 올바르게 되었는지 확인하기 위해 테스트 코드를 작성하고 실행한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파일 생성:&lt;/b&gt; src 폴더를 만들고 그 안에 index.ts를 생성한다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// src/index.ts
console.log(&quot;Hello New Project&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방법 A: TSC 컴파일 후 실행 (Node.js)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;48&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckvBuN/dJMcaf6bMNr/0Xl0KSS4l1s1IwPAyX0K00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckvBuN/dJMcaf6bMNr/0Xl0KSS4l1s1IwPAyX0K00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckvBuN/dJMcaf6bMNr/0Xl0KSS4l1s1IwPAyX0K00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckvBuN%2FdJMcaf6bMNr%2F0Xl0KSS4l1s1IwPAyX0K00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;636&quot; height=&quot;48&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;48&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;방법 B: TSX로 즉시 실행 (권장)&lt;/b&gt; 별도의 ts-node 설정 없이, 설치된 tsx를 이용해 바로 실행한다.
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;32&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lSPo9/dJMcaaw2Wd1/dLt5MzjY41U6AaKlr6RKt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lSPo9/dJMcaaw2Wd1/dLt5MzjY41U6AaKlr6RKt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lSPo9/dJMcaaw2Wd1/dLt5MzjY41U6AaKlr6RKt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlSPo9%2FdJMcaaw2Wd1%2FdLt5MzjY41U6AaKlr6RKt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;32&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;32&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/526</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EA%B8%B0%EB%B3%B8-%ED%83%80%EC%9E%85Basic-Types%EA%B3%BC-%EC%8B%A4%EC%8A%B5-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95#entry526comment</comments>
      <pubDate>Wed, 10 Dec 2025 18:52:52 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입스크립트 컴파일러 옵션 설정 (tsconfig.json)</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EC%98%B5%EC%85%98-%EC%84%A4%EC%A0%95-tsconfigjson</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;431&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KV4G2/dJMcagquslg/E1EXxBOZrdQx9873ebeKUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KV4G2/dJMcagquslg/E1EXxBOZrdQx9873ebeKUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KV4G2/dJMcagquslg/E1EXxBOZrdQx9873ebeKUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKV4G2%2FdJMcagquslg%2FE1EXxBOZrdQx9873ebeKUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;887&quot; height=&quot;431&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;431&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트 컴파일러는 소스 코드를 분석하여 타입 오류를 검사하고 자바스크립트 코드로 변환한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;이 과정에서 &lt;b&gt;얼마나 엄격하게 검사할지&lt;/b&gt;, &lt;b&gt;어떤 버전의 자바스크립트로 변환할지&lt;/b&gt; 등 세부적인 동작을 설정할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이러한 설정은 프로젝트 루트 경로에 있는 tsconfig.json 파일에 정의하며, 프로젝트의 성격에 맞춰 최적화된 환경을 구성하는 데 사용된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;설정 파일 생성&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r2fJx/dJMcabW1gnX/YbVXSPwODmom5gV7bUg5UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r2fJx/dJMcabW1gnX/YbVXSPwODmom5gV7bUg5UK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r2fJx/dJMcabW1gnX/YbVXSPwODmom5gV7bUg5UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr2fJx%2FdJMcabW1gnX%2FYbVXSPwODmom5gV7bUg5UK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;592&quot; height=&quot;86&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;터미널에서 &lt;b&gt;tsc --init 명령어&lt;/b&gt;를 입력하면 기본 설정이 담긴 tsconfig.json이 자동 생성된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;하지만 학습을 위해 기본 내용을 모두 지우고 빈 객체({}) 상태에서 필요한 옵션을 하나씩 추가하며 익혀본다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEpcfQzrKRAxUAAAAAHQAAAAAQjgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1765356086462&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;컴파일 대상 설정: include&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;include 옵션은 컴파일러에게 &lt;b&gt;어떤 파일들을 컴파일할지&lt;/b&gt; 알려주는 경로 설정이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;이 옵션을 설정하면 파일을 하나씩 지정하지 않고 폴더 단위로 컴파일할 수 있다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEpcfQzrKRAxUAAAAAHQAAAAAQjwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;include&quot;: [&quot;src&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;효과&lt;/span&gt;:&lt;/b&gt; tsc 명령어 입력 시, src 폴더 내의 모든 타입스크립트 파일이 자동으로 컴파일된다. (js파일도 생기는것임)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;주요 컴파일러 옵션 (compilerOptions)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;상세 옵션은 compilerOptions 객체 안에 정의한다.&lt;/u&gt;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;target: 자바스크립트 버전 설정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;컴파일 결과물로 생성될 자바스크립트 코드의 버전을 결정한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEpcfQzrKRAxUAAAAAHQAAAAAQkAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ES5&quot;
  },
  &quot;include&quot;: [&quot;src&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ES5:&lt;/b&gt; 화살표 함수(() =&amp;gt; {})가 function 키워드로 변환되는 등, 구형 브라우저 호환성을 위해 낮은 버전의 문법으로 변환된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ESNext:&lt;/b&gt; 최신 자바스크립트 문법을 그대로 유지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;module: 모듈 시스템 설정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 모듈을 불러오고 내보내는 방식을 결정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGi8cU/dJMcajgoLS4/5vrT4K0NssruXkixrZpCP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGi8cU/dJMcajgoLS4/5vrT4K0NssruXkixrZpCP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGi8cU/dJMcajgoLS4/5vrT4K0NssruXkixrZpCP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGi8cU%2FdJMcajgoLS4%2F5vrT4K0NssruXkixrZpCP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;673&quot; height=&quot;362&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEpcfQzrKRAxUAAAAAHQAAAAAQkQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: { &quot;target&quot;: &quot;esnext&quot;, &quot;module&quot;: &quot;CommonJS&quot; },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CommonJS:&lt;/b&gt; require, exports 문법으로 변환된다. (Node.js 기본 환경 등에서 주로 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6gnMa/dJMcahJImCC/lu17NLoKoIijDtAtCf7eF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6gnMa/dJMcahJImCC/lu17NLoKoIijDtAtCf7eF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6gnMa/dJMcahJImCC/lu17NLoKoIijDtAtCf7eF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6gnMa%2FdJMcahJImCC%2Flu17NLoKoIijDtAtCf7eF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;676&quot; height=&quot;362&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1765357075504&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: { &quot;target&quot;: &quot;esnext&quot;, &quot;module&quot;: &quot;ESNext&quot; },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ESNext:&lt;/b&gt; import, export 문법을 그대로 유지한다. (최신 브라우저 및 모듈 환경에서 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;outDir: 결과물 출력 경로&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;컴파일된 자바스크립트 파일(.js)이 생성될 위치를 지정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;227&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGRQls/dJMcacIo3U0/erywVBjyUHFNkSrkQSpNgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGRQls/dJMcacIo3U0/erywVBjyUHFNkSrkQSpNgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGRQls/dJMcacIo3U0/erywVBjyUHFNkSrkQSpNgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGRQls%2FdJMcacIo3U0%2FerywVBjyUHFNkSrkQSpNgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;227&quot; height=&quot;307&quot; data-origin-width=&quot;227&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEpcfQzrKRAxUAAAAAHQAAAAAQkgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;esnext&quot;,
    &quot;module&quot;: &quot;esnext&quot;,
    &quot;outDir&quot;: &quot;dist&quot;
  },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;효과&lt;/span&gt;:&lt;/b&gt; 컴파일 결과물이 소스 폴더(src)와 섞이지 않고 dist 폴더에 별도로 모이게 되어 관리가 용이하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;strict: 엄격한 타입 검사&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트의 타입 검사 강도를 최상으로 설정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE7idA/dJMcab3MXXh/nsNAsekR5ovRdnbf0Y0G30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE7idA/dJMcab3MXXh/nsNAsekR5ovRdnbf0Y0G30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE7idA/dJMcab3MXXh/nsNAsekR5ovRdnbf0Y0G30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE7idA%2FdJMcab3MXXh%2FnsNAsekR5ovRdnbf0Y0G30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;783&quot; height=&quot;603&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;603&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEpcfQzrKRAxUAAAAAHQAAAAAQkwE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ESNext&quot;,
    &quot;module&quot;: &quot;ESNext&quot;,
    &quot;outDir&quot;: &quot;dist&quot;,
    &quot;strict&quot;: true
  },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;효과&lt;/span&gt;:&lt;/b&gt; strict: true를 설정하면 잠재적인 오류를 막기 위해 엄격한 규칙이 적용된다. (false하면 오류 사라짐)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시:&lt;/b&gt; 함수의 매개변수 타입을 지정하지 않으면(Any 타입 추론), 컴파일러가 이를 오류로 간주하여 빨간 줄을 표시한다. 안전한 코드를 위해 필수적으로 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;30&quot; data-ke-size=&quot;size23&quot;&gt;moduleDetection: 모듈 감지 방식&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Su6Li/dJMcaaw2VA1/N90D43bI1VC1G7ktMswrw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Su6Li/dJMcaaw2VA1/N90D43bI1VC1G7ktMswrw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Su6Li/dJMcaaw2VA1/N90D43bI1VC1G7ktMswrw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSu6Li%2FdJMcaaw2VA1%2FN90D43bI1VC1G7ktMswrw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;847&quot; height=&quot;350&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;블록 범위 변수 'a'를 다시 선언할 수 없다. =&amp;gt; 동일한 변수를 똑같은 스코프에 2번 선언한 것을 의미&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 모든 파일을&lt;b&gt; 전역 모듈&lt;/b&gt;로 보고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size26&quot;&gt;해결방법 1. export {} 작성&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6okTs/dJMcaaX7gIe/Vnkdl5xHHjJGKY6egQN7H0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6okTs/dJMcaaX7gIe/Vnkdl5xHHjJGKY6egQN7H0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6okTs/dJMcaaX7gIe/Vnkdl5xHHjJGKY6egQN7H0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6okTs%2FdJMcaaX7gIe%2FVnkdl5xHHjJGKY6egQN7H0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;879&quot; height=&quot;352&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;31&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;31&quot;&gt;해결방법 2. &lt;b&gt;moduleDetection&lt;/b&gt; 사용&lt;/h2&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트 파일이 전역 스코프(Global Scope)가 아닌 &lt;b&gt;독립된(개별된) 모듈&lt;/b&gt;로 취급되도록 강제한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBDDoM/dJMcacBDpOT/FgVRV3tNNKC0sMNIsbo8g0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBDDoM/dJMcacBDpOT/FgVRV3tNNKC0sMNIsbo8g0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBDDoM/dJMcacBDpOT/FgVRV3tNNKC0sMNIsbo8g0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBDDoM%2FdJMcacBDpOT%2FFgVRV3tNNKC0sMNIsbo8g0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;897&quot; height=&quot;724&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;* module 설정에 따라 .js에 export 방식은 달라짐!&lt;/i&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiEpcfQzrKRAxUAAAAAHQAAAAAQlAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ESNext&quot;,
    &quot;module&quot;: &quot;ESNext&quot;,
    &quot;outDir&quot;: &quot;dist&quot;,
    &quot;strict&quot;: true,
    &quot;moduleDetection&quot;: &quot;force&quot;
  },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;33&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;배경&lt;/span&gt;:&lt;/b&gt; 자바스크립트는 기본적으로 import나 export가 없는 파일을 전역 스크립트로 취급한다. 이로 인해 서로 다른 파일에서 같은 이름의 변수를 선언하면 충돌 오류가 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;효과&lt;/span&gt;:&lt;/b&gt; force로 설정하면 모든 파일에 자동으로 export {} 코드가 컴파일 과정에 삽입된 것처럼 처리되어, 파일마다 독립적인 스코프를 갖게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;skipLibCheck: 라이브러리 타입 검사 생략&lt;/h3&gt;
&lt;pre id=&quot;code_1765358969031&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ESNext&quot;,
    &quot;module&quot;: &quot;ESNext&quot;,
    &quot;outDir&quot;: &quot;dist&quot;,
    &quot;strict&quot;: true,
    &quot;moduleDetection&quot;: &quot;force&quot;,
    &quot;skipLibCheck&quot;: true
  },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;배경&lt;/span&gt;:&lt;/b&gt; 프로젝트에 설치된 외부 라이브러리(node_modules)들의 타입 정의 파일끼리 버전이 맞지 않거나 충돌이 발생하면, 내가 작성한 코드가 아님에도 컴파일 에러가 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;효과&lt;/span&gt;:&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;5,1,1&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;불필요한 에러 방지:&lt;/b&gt; 외부 라이브러리 내부의 타입 에러로 인해 전체 컴파일이 실패하는 것을 막아준다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일 속도 향상:&lt;/b&gt; 방대한 양의 라이브러리 타입 정의 파일을 일일이 검사하지 않으므로 컴파일 성능이 크게 향상된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;권장&lt;/span&gt;: 대부분의 최신 프로젝트에서는 true로 설정하는 것이 일반적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot;&gt;https://inf.run/aGJcF&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765359110754&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&quot; data-og-description=&quot;현재 평점 5.0점 수강생 13,375명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://inf.run/aGJcF&quot; data-og-url=&quot;https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%ED%81%AC%EA%B8%B0-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qlueY/hyZPhnoNIe/MklB28rKxGZTMHEFYIHv80/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/bNAsJp/hyZOz2NeEI/VayvvB1D5tZXB0i0LiY7h0/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/pcpDL/hyZPkLcaRr/oWItQ41KyUCLzxOYhqK7jK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499&quot;&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inf.run/aGJcF&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qlueY/hyZPhnoNIe/MklB28rKxGZTMHEFYIHv80/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/bNAsJp/hyZOz2NeEI/VayvvB1D5tZXB0i0LiY7h0/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/pcpDL/hyZPkLcaRr/oWItQ41KyUCLzxOYhqK7jK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;현재 평점 5.0점 수강생 13,375명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>컴파일러</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/525</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EC%98%B5%EC%85%98-%EC%84%A4%EC%A0%95-tsconfigjson#entry525comment</comments>
      <pubDate>Wed, 10 Dec 2025 18:31:59 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] Private Class Fields (#)</title>
      <link>https://recordoftheday.tistory.com/entry/JavaScript-Private-Class-Fields</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;class의 속성(property)들은 public하며 class외부에서 읽히고 수정될 수 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES2019에서 #을 추가해 private class 필드를 선언할 수 있게 되었다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Private Instance Fields (#변수)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;&quot;내 차 대시보드 안의 잠긴 서랍&quot;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;new Car()로 뽑은 &lt;b&gt;내 자동차(인스턴스)&lt;/b&gt;만이 가질 수 있는 비밀 데이터&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름 앞에 반드시 &lt;b&gt;#&lt;/b&gt; 을 붙여야함 (이게 자물쇠야!)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;밖에서는 절대 못 열음&lt;/b&gt;&amp;nbsp;(car.#secret 하면 에러 뻥!)&lt;/li&gt;
&lt;li&gt;반드시 클래스 맨 윗줄에 &quot;나 이거 쓸 거야&quot;라고 선언해야함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1765268663147&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Car {
  #fuel; // 1. 선언 (자물쇠 달린 연료통)

  constructor() {
    this.#fuel = 100; // 2. 내 차니까 접근 가능
  }
}
const myCar = new Car();
// myCar.#fuel = 0; //   삐-! 에러! (밖에서는 못 건드림)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Private Instance Methods (#함수())&lt;/h2&gt;
&lt;blockquote data-path-to-node=&quot;11&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;11,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;운전자는 몰라도 되는, 엔진 내부의 비밀 동작&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;자동차 내부에서&amp;nbsp;자기끼리만 신호를 주고받을 때&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;쓰는 기능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt; 운전자가 직접 &quot;엔진 온도 체크해!&quot;라고 안 하지? 차가 알아서 함&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;용도:&lt;/b&gt; 주로 &lt;b&gt;'검증(Validation)'&lt;/b&gt;이나 '&lt;b&gt;복잡한 계산&lt;/b&gt;'을 숨길 때 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; Getter나 Setter도 #을 붙여서 비밀로 만들 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1765268806558&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Car {
  move(speed) {
    if (this.#checkEngine(speed)) { // 내부에서만 몰래 호출
      console.log(&quot;출발!&quot;);
    }
  }

  #checkEngine(speed) { //   비밀 함수
    return speed &amp;lt; 200; // 엔진 과부하 체크
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Private Static Fields &amp;amp; Methods (static #변수)&lt;/h2&gt;
&lt;blockquote data-path-to-node=&quot;16&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;16,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;자동차 공장 본사의 1급 기밀 금고&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설명:&lt;/b&gt; 이건 개별 자동차(소나타, 아반떼)는 몰라. 오직 &lt;b&gt;Car라는 공장(클래스) 자체&lt;/b&gt;만 아는 비밀&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주의할 점 (상속의 함정):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;this를 쓰면 위험!&lt;/li&gt;
&lt;li&gt;공장장(Class)이 바뀌면 금고 문이 안 열림&lt;/li&gt;
&lt;li&gt;그래서 Static Private을 쓸 때는 this 대신 &lt;b&gt;클래스 이름(Car)을 직접 부르는 게 안전&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1765268843995&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CarFactory {
  static #SECRET_CODE = 1234; // 공장 기밀 번호

  static getCode() {
    // return this.#SECRET_CODE; // ⚠️ 위험! 상속받은 공장(자식 클래스)에서는 에러 날 수 있음.
    return CarFactory.#SECRET_CODE; // ✅ 안전! 공장 이름을 직접 불러라.
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  핵심 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;캡슐화(Encapsulation)의 완성:&lt;/b&gt; #을 붙이면 &lt;b&gt;&quot;외부 접근 절대 불가&quot;&lt;/b&gt; 상태가 된다. 개발자의 실수(오작동)를 원천 봉쇄할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;선언은 필수:&lt;/b&gt; #변수는 반드시 클래스 최상단에 적어줘야 한다. 안 그러면 자바스크립트가 &quot;이게 뭐야?&quot; 하고 에러를 낸다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Static의 함정:&lt;/b&gt; static #을 쓸 때는 this 때문에 에러가 자주 나니, 웬만하면 &lt;b&gt;클래스 이름을 명시&lt;/b&gt;하는 습관을 들이자!&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  JavaScript</category>
      <category>#</category>
      <category>private</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/524</guid>
      <comments>https://recordoftheday.tistory.com/entry/JavaScript-Private-Class-Fields#entry524comment</comments>
      <pubDate>Tue, 9 Dec 2025 17:29:26 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입스크립트 실습 환경 설정 및 Hello World</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8B%A4%EC%8A%B5-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%8F-Hello-World</link>
      <description>&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;프로젝트 폴더 생성 및 초기화&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;실습 코드를 관리할 폴더를 생성하고 Node.js 프로젝트를 초기화한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;폴더 생성:&lt;/b&gt; 원하는 위치에 onebite-typescript 폴더를 생성하고, 그 하위에 section01 폴더를 만든다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로젝트 초기화:&lt;/b&gt; 터미널에서 section01 폴더로 이동한 뒤 아래 명령어를 입력한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6,1,2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;npm init-y 옵션을 사용하면 기본 설정값으로 빠르게 초기화된다. 완료 시 package.json 파일이 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1765203035297&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm init&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;필수 패키지 설치: @types/node&lt;/h2&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트 프로젝트를 시작할 때 가장 먼저 @types/node를 설치해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1765203097574&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; npm i @types/node&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjkvIWJiq6RAxUAAAAAHQAAAAAQtgI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설치 이유&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 기본적으로 자바스크립트 내장 기능(Node.js의 console, process 등)에 대한 타입 정보를 알지 못한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;이 정보를 담고 있는 @types/node를 설치하지 않으면 컴파일 과정에서 타입 에러가 발생한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;설치가 완료되면 node_modules/@types 폴더 내에 Node.js 관련 타입 정의 파일(.d.ts)이 생성된 것을 확인할 수 있다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;타입스크립트 컴파일러(TSC) 설치&lt;/h2&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트 코드를 자바스크립트로 변환해 주는 컴파일러를 설치한다. 실습 편의를 위해 전역(Global)으로 설치한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설치 명령어&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765203265803&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install typescript -g&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jkk6n/dJMcafd2IfT/rAXOg2cn6X1pprPES5q3T0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jkk6n/dJMcafd2IfT/rAXOg2cn6X1pprPES5q3T0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jkk6n/dJMcafd2IfT/rAXOg2cn6X1pprPES5q3T0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJkk6n%2FdJMcafd2IfT%2FrAXOg2cn6X1pprPES5q3T0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;252&quot; height=&quot;84&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;84&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjkvIWJiq6RAxUAAAAAHQAAAAAQtwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;tsc -v
# Version 5.x.x 와 같이 버전 정보가 출력되면 성공&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size26&quot;&gt;Hello World 코드 작성&lt;/h2&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트 루트 경로에 src 폴더를 만들고 index.ts 파일을 생성한다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjkvIWJiq6RAxUAAAAAHQAAAAAQuAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;console.log(&quot;Hello TypeScript&quot;);
const a: number = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size26&quot;&gt;실행 방법 1: TSC (정석적인 방법)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트의 표준 실행 방식은 &lt;b&gt;[컴파일&lt;/b&gt; &amp;rarr;&amp;nbsp;&lt;b&gt;실행]&lt;/b&gt;의 2단계 과정을 거친다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;24&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;컴파일:&lt;/b&gt; tsc 명령어로 타입스크립트 파일을 자바스크립트로 변환한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;24,0,2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 결과, 같은 폴더에 index.js 파일이 생성된다. 내용을 확인해보면 타입 정보(: number)가 제거되고 순수 자바스크립트 코드(var a = 1;)로 변환된 것을 볼 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;tsc src/index.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행:&lt;/b&gt; Node.js로 변환된 자바스크립트 파일을 실행한다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;node src/index.js
# 출력: Hello TypeScript
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-path-to-node=&quot;25&quot; data-ke-size=&quot;size26&quot;&gt;실행 방법 2: TSX (간편한 방법)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;매번 컴파일하고 실행하는 과정은 번거롭다. &lt;b&gt;TSX(TypeScript Execute)&lt;/b&gt; 도구를 사용하면 명령어 한 번으로 타입스크립트 코드를 즉시 실행할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;(과거에는 ts-node를 주로 사용했으나, Node.js 최신 버전 호환성 문제로 현재는 tsx가 표준으로 자리 잡았다.)&lt;/i&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TSX 설치&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjkvIWJiq6RAxUAAAAAHQAAAAAQuwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;npm i -g tsx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(npm install tsx -g로 했을때 전 npm error가 났음)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;29&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;29&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TSX 실행&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjkvIWJiq6RAxUAAAAAHQAAAAAQvAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;tsx src/index.ts
# 출력: Hello TypeScript&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;tsx는 내부적으로 코드를 변환하고 실행까지 한 번에 처리해 주며, 별도의 .js 파일을 생성하지 않아 개발 시 매우 유용하다.&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>실행</category>
      <category>타입스크립트</category>
      <category>타입스크립트실행</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/523</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8B%A4%EC%8A%B5-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%8F-Hello-World#entry523comment</comments>
      <pubDate>Mon, 8 Dec 2025 23:25:29 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입스크립트의 동작 원리</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC</link>
      <description>&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;일반적인 프로그래밍 언어의 컴파일 과정&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5y49k/dJMcagRxTui/2drOX8DZF0R5izoJNo46Zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5y49k/dJMcagRxTui/2drOX8DZF0R5izoJNo46Zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5y49k/dJMcagRxTui/2drOX8DZF0R5izoJNo46Zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5y49k%2FdJMcagRxTui%2F2drOX8DZF0R5izoJNo46Zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;우리가 작성하는 프로그래밍 언어(Java, JavaScript 등)는 인간이 이해하기 쉬운 형태다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;하지만 컴퓨터는 이를 바로 이해하지 못하고, 기계어(0과 1)나 바이트코드 같은 단순한 형태만 인식할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;&lt;u&gt; 사람이 작성한 코드를 컴퓨터가 이해할 수 있는 형태로 변환하는 과정이 필요하며, 이를 &lt;b&gt;컴파일(Compile)&lt;/b&gt;이라 하고, 변환해 주는 도구를 &lt;b&gt;컴파일러(Compiler)&lt;/b&gt;&lt;/u&gt;라고 한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wntCX/dJMcacVUPih/ikX4G0ZTjQI2iW3KtKkus0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wntCX/dJMcacVUPih/ikX4G0ZTjQI2iW3KtKkus0/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wntCX/dJMcacVUPih/ikX4G0ZTjQI2iW3KtKkus0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwntCX%2FdJMcacVUPih%2FikX4G0ZTjQI2iW3KtKkus0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wzCTg/dJMcafSEiFl/rpRXT4glWL0B7B4MHQK910/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wzCTg/dJMcafSEiFl/rpRXT4glWL0B7B4MHQK910/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wzCTg/dJMcafSEiFl/rpRXT4glWL0B7B4MHQK910/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwzCTg%2FdJMcafSEiFl%2FrpRXT4glWL0B7B4MHQK910%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSccOp/dJMcahQswnt/kZ51IwHBNMuCZUNBUQowrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSccOp/dJMcahQswnt/kZ51IwHBNMuCZUNBUQowrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSccOp/dJMcahQswnt/kZ51IwHBNMuCZUNBUQowrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSccOp%2FdJMcahQswnt%2FkZ51IwHBNMuCZUNBUQowrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;444&quot; height=&quot;250&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;일반적인&lt;b&gt; 컴파일 단계&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;소스 코드 작성:&lt;/b&gt; 개발자가 코드를 작성한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AST(추상 문법 트리) 변환:&lt;/b&gt; 컴파일러가 코드를 파싱하여 공백이나 주석을 제거하고, 코드의 구조를 트리 형태의 자료구조인 &lt;b&gt;AST(Abstract&lt;/b&gt;&amp;nbsp;&lt;b&gt;Syntax Tree)&lt;/b&gt;로 변환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;바이트코드 생성:&lt;/b&gt; 생성된 AST를 컴퓨터가 이해할 수 있는 &lt;b&gt;바이트코드(Bytecode)&lt;/b&gt;로 변환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행:&lt;/b&gt; 컴퓨터가 바이트코드를 실행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;타입스크립트의 컴파일 과정&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9vt8x/dJMcabpasrR/3msZkTwAkTfRFZTF4X1fnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9vt8x/dJMcabpasrR/3msZkTwAkTfRFZTF4X1fnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9vt8x/dJMcabpasrR/3msZkTwAkTfRFZTF4X1fnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9vt8x%2FdJMcabpasrR%2F3msZkTwAkTfRFZTF4X1fnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트도 컴파일 과정을 거치지만&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;최종 산출물이 바이트코드가 아닌 &lt;b&gt;자바스크립트(JavaScript)&lt;/b&gt;라는 점에서 큰 차이가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uzWdf/dJMcah3ZA11/5T2Jhcbpfjrb752NGBgrmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uzWdf/dJMcah3ZA11/5T2Jhcbpfjrb752NGBgrmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uzWdf/dJMcah3ZA11/5T2Jhcbpfjrb752NGBgrmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuzWdf%2FdJMcah3ZA11%2F5T2Jhcbpfjrb752NGBgrmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOiwEi/dJMcaaqgzba/nK8Ua3XUlPe1Tk3wqIUKik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOiwEi/dJMcaaqgzba/nK8Ua3XUlPe1Tk3wqIUKik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOiwEi/dJMcaaqgzba/nK8Ua3XUlPe1Tk3wqIUKik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOiwEi%2FdJMcaaqgzba%2FnK8Ua3XUlPe1Tk3wqIUKik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;타입스크립트의 컴파일 단계&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;소스 코드 작성:&lt;/b&gt; 타입스크립트 코드를 작성한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AST 변환:&lt;/b&gt; 일반적인 언어와 마찬가지로 코드를 AST로 변환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타입 검사 (Type Checking):&lt;/b&gt; &lt;b&gt;(핵심 단계)&lt;/b&gt; 변환된 AST를 기반으로 코드에 타입 오류가 없는지 검사한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;검사 실패:&lt;/b&gt; 코드에 타입 오류가 있다면 컴파일이 중단되고 에러가 발생한다. (자바스크립트 생성 안 됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검사 성공:&lt;/b&gt; 오류가 없다면 다음 단계로 넘어간다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바스크립트 변환:&lt;/b&gt; AST를 바이트코드가 아닌 &lt;b&gt;자바스크립트 코드&lt;/b&gt;로 변환한다. 이때 타입 관련 코드는 모두 제거된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;핵심 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;15&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;컴파일 타임 에러 검출:&lt;/b&gt; 타입 검사를 통과하지 못하면 자바스크립트 코드가 생성되지 않는다. 즉, 생성된 자바스크립트 코드는 '타입 검사가 완료된 안전한 코드'임을 보장받는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타입 정보 소거:&lt;/b&gt; 컴파일이 완료된 자바스크립트 코드에는 타입스크립트의 문법(Type Annotation)이 남아있지 않다. 따라서 브라우저나 Node.js는 아무 문제 없이 순수한 자바스크립트를 실행할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-path-to-node=&quot;16&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;16,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론:&lt;/b&gt; 타입스크립트는 자바스크립트를 실행하기 전, &lt;b&gt;미리 코드를 검사하여 안전성을 확보해 주는 도구&lt;/b&gt; 역할을 수행한 뒤 순수한 자바스크립트 코드를 만들어낸다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inf.run/aGJcF&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765202234907&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&quot; data-og-description=&quot;현재 평점 5.0점 수강생 13,366명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://inf.run/aGJcF&quot; data-og-url=&quot;https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%ED%81%AC%EA%B8%B0-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bbxWKx/hyZOBTz8MH/vI92aWm5zF63PW1v0lOjSK/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/DbYB1/hyZO8QQpOL/GrrGF8g7usgyNEGJ2wHTjk/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/nPQYa/hyZOLomQxC/AObgz2swT95GdBDLnD7mlK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499&quot;&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inf.run/aGJcF&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bbxWKx/hyZOBTz8MH/vI92aWm5zF63PW1v0lOjSK/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/DbYB1/hyZO8QQpOL/GrrGF8g7usgyNEGJ2wHTjk/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/nPQYa/hyZOLomQxC/AObgz2swT95GdBDLnD7mlK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;현재 평점 5.0점 수강생 13,366명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>동작원리</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/522</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC#entry522comment</comments>
      <pubDate>Mon, 8 Dec 2025 22:57:35 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 자바스크립트의 한계점과 타입스크립트의 해결책</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%95%9C%EA%B3%84%EC%A0%90%EA%B3%BC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%95%B4%EA%B2%B0%EC%B1%85</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sMjll/dJMcai2Q1aM/a4yaBeDAikukDVLS43P8hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sMjll/dJMcai2Q1aM/a4yaBeDAikukDVLS43P8hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sMjll/dJMcai2Q1aM/a4yaBeDAikukDVLS43P8hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsMjll%2FdJMcai2Q1aM%2Fa4yaBeDAikukDVLS43P8hk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;908&quot; height=&quot;434&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;모든 프로그래밍 언어에는 &lt;b&gt;타입 시스템(Type System)&lt;/b&gt;이 존재한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;이는 언어에서 사용할 수 있는 값의 종류를 정의하고, 코드를 언제, 어떻게 검사할지 결정하는 규칙의 집합이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kK4RG/dJMcaiu1BNW/e9oSWhuDBjikIuGFc4A80k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kK4RG/dJMcaiu1BNW/e9oSWhuDBjikIuGFc4A80k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kK4RG/dJMcaiu1BNW/e9oSWhuDBjikIuGFc4A80k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkK4RG%2FdJMcaiu1BNW%2Fe9oSWhuDBjikIuGFc4A80k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트의 한계를 이해하고 타입스크립트의 필요성을 파악하기 위해서는,&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;우선 이 타입 시스템의 두 가지 분류인 &lt;b&gt;동적 타입 시스템&lt;/b&gt;과 &lt;b&gt;정적 타입 시스템&lt;/b&gt;을 이해해야 한다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;동적 타입 시스템 (Dynamic Type System)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wT4ho/dJMcabipyZ0/LwJpViXorDaQyJKskjWdPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wT4ho/dJMcabipyZ0/LwJpViXorDaQyJKskjWdPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wT4ho/dJMcabipyZ0/LwJpViXorDaQyJKskjWdPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwT4ho%2FdJMcabipyZ0%2FLwJpViXorDaQyJKskjWdPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트나 파이썬이 채택한 방식이다. 변수의 타입이 코드가&lt;b&gt; 실행되는 도중(Runtime)&lt;/b&gt;에 결정된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; 변수를 선언할 때 타입을 미리 지정할 필요가 없다. 변수에 담기는 값에 따라 타입이 유동적으로 바뀐다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점:&lt;/b&gt; 문법이 유연하고 코드 작성이 간결하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점:&lt;/b&gt; 실행 전에는 타입 오류를 감지할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;치명적인 문제점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 런타임 에러&lt;/b&gt; 자바스크립트는 타입이 자유롭기 때문에,&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;숫자형 변수에 문자열 전용 메서드를 사용해도 실행 자체는 가능하다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실행 도중 해당 라인에 도달하면 프로그램이 강제 종료되는 &lt;b&gt;런타임 에러&lt;/b&gt;가 발생한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;간단한 프로그램이라면 바로 수정할 수 있지만,&amp;nbsp;복잡한 대규모 서비스에서 특정 상황에만 발생하는&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;  런타임 에러는 서비스 전체를 마비시키는 치명적인 장애로 이어질 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;정적 타입 시스템 (Static Type System)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kwXAx/dJMcafSEizz/IpkzTBTrQDv7uqfYu13ZM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kwXAx/dJMcafSEizz/IpkzTBTrQDv7uqfYu13ZM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kwXAx/dJMcafSEizz/IpkzTBTrQDv7uqfYu13ZM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkwXAx%2FdJMcafSEizz%2FIpkzTBTrQDv7uqfYu13ZM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;C나 Java가 채택한 방식이다. 변수의 타입을 코드 &lt;b&gt;실행전(Compile Time)&lt;/b&gt;에&amp;nbsp;결정한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징:&lt;/b&gt; 변수 선언 시 타입을 무조건 명시해야 한다. (예: int a = 10;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점:&lt;/b&gt; 컴파일 단계에서 타입 오류를 감지하므로 실행 전에 문제를 차단할 수 있다. 안정성이 매우 높다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점:&lt;/b&gt; 모든 변수에 일일이 타입을 지정해야 하므로 코드가 길어지고 작성이 번거롭다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;타입스크립트의 해결책: 점진적 타입 시스템 (Gradual Type System)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVqtnp/dJMcaa4RIue/0dt5AQAy190iM1uNyHPDd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVqtnp/dJMcaa4RIue/0dt5AQAy190iM1uNyHPDd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVqtnp/dJMcaa4RIue/0dt5AQAy190iM1uNyHPDd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVqtnp%2FdJMcaa4RIue%2F0dt5AQAy190iM1uNyHPDd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;944&quot; height=&quot;516&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 동적 타입 시스템의 '&lt;span style=&quot;background-color: #99cefa;&quot;&gt;유연함&lt;/span&gt;'과 정적 타입 시스템의 '&lt;span style=&quot;background-color: #99cefa;&quot;&gt;안정성&lt;/span&gt;'을 모두 취하기 위해 &lt;b&gt;점진적 타입 시스템(Gradual Type System)&lt;/b&gt;을 사용한다. =&amp;gt; &lt;u&gt;모든 변수에 타입을 일일이 지정할 필요 없다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;작동 방식&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;실행 전 검사:&lt;/b&gt; 정적 타입 시스템처럼 코드를 실행하기 전에 타입을 검사하여 오류를 미리 포착한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타입 추론 (Type Inference):&lt;/b&gt; 모든 변수에 일일이 타입을 지정할 필요가 없다. 변수에 할당된 값을 기준으로 타입을 자동으로 추론한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv6j7Y/dJMcafd2HOA/mPr2ws84lVB98A20fyUMr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv6j7Y/dJMcafd2HOA/mPr2ws84lVB98A20fyUMr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv6j7Y/dJMcafd2HOA/mPr2ws84lVB98A20fyUMr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv6j7Y%2FdJMcafd2HOA%2FmPr2ws84lVB98A20fyUMr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 자바스크립트처럼 문법이 간결하면서도, Java처럼 실행 전에 오류를 잡아내는 안전한 언어다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;이러한 특징 덕분에 개발자는 번거로운 타입 선언 없이도 안전하게 대규모 프로그램을 개발할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inf.run/aGJcF&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765201171508&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&quot; data-og-description=&quot;현재 평점 5.0점 수강생 13,366명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://inf.run/aGJcF&quot; data-og-url=&quot;https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%ED%81%AC%EA%B8%B0-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bbxWKx/hyZOBTz8MH/vI92aWm5zF63PW1v0lOjSK/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/DbYB1/hyZO8QQpOL/GrrGF8g7usgyNEGJ2wHTjk/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/nPQYa/hyZOLomQxC/AObgz2swT95GdBDLnD7mlK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499&quot;&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inf.run/aGJcF&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bbxWKx/hyZOBTz8MH/vI92aWm5zF63PW1v0lOjSK/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/DbYB1/hyZO8QQpOL/GrrGF8g7usgyNEGJ2wHTjk/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/nPQYa/hyZOLomQxC/AObgz2swT95GdBDLnD7mlK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;현재 평점 5.0점 수강생 13,366명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/521</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%95%9C%EA%B3%84%EC%A0%90%EA%B3%BC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%95%B4%EA%B2%B0%EC%B1%85#entry521comment</comments>
      <pubDate>Mon, 8 Dec 2025 22:42:41 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입스크립트 소개</title>
      <link>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%86%8C%EA%B0%9C</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;타입스크립트 창시자&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tUCs3/dJMcabW0z7h/8acs1UbybXklK8g56thKik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tUCs3/dJMcabW0z7h/8acs1UbybXklK8g56thKik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tUCs3/dJMcabW0z7h/8acs1UbybXklK8g56thKik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtUCs3%2FdJMcabW0z7h%2F8acs1UbybXklK8g56thKik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트는 2012년 마이크로소프트의 &lt;b&gt;앤더스 하일스버그(Anders Hejlsberg)&lt;/b&gt;가 개발했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C#의 창시자가 만든 만큼 두 언어는 구조적으로 유사하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 오픈소스로 운영되어 전 세계 개발자의 기여 속에 지속해서 발전하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타입스크립트 = 자바스크립트의 확장판&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3mgnW/dJMcafZplgy/oWbcojwrdZ6MUlC8bkmig1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3mgnW/dJMcafZplgy/oWbcojwrdZ6MUlC8bkmig1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3mgnW/dJMcafZplgy/oWbcojwrdZ6MUlC8bkmig1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3mgnW%2FdJMcafZplgy%2FoWbcojwrdZ6MUlC8bkmig1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhZI2d/dJMcajm9A3D/Y6OYZUpbYqkledYQLAH4nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhZI2d/dJMcajm9A3D/Y6OYZUpbYqkledYQLAH4nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhZI2d/dJMcajm9A3D/Y6OYZUpbYqkledYQLAH4nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhZI2d%2FdJMcajm9A3D%2FY6OYZUpbYqkledYQLAH4nk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자바스크립트의 슈퍼셋(Superset)&lt;/b&gt; 타입스크립트는 완전히 새로운 언어가 아니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트의 문법은 그대로 유지하되, &lt;b&gt;타입(Type)&lt;/b&gt; 관련 기능을 추가하여 안정성을 높인 &lt;b&gt;자바스크립트의 확장판&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;기존 자바스크립트 코드에 변수의 타입(예: : number)을 정의하는 문법만 추가하면 타입스크립트 코드가 된다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &lt;u&gt;자바스크립트에 익숙하다면 추가 기능만 익혀 프로젝트에 즉시 적용할 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;시장 입지와 인기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;높은 사용률:&lt;/b&gt; StateOfJS(2022) 설문 결과, 자바스크립트 개발자 100명 중 약 89명이 이미 사용 중이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;채용 필수 요건:&lt;/b&gt; 프론트엔드와 백엔드를 막론하고 대부분의 채용 공고에서 핵심 역량으로 요구한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발자 선호:&lt;/b&gt; 프로그래머스 등 주요 설문에서 '가장 배우고 싶은 언어' 상위권에 선정되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size26&quot;&gt;도입 배경: 왜 자바스크립트만으로는 부족한가?&lt;/h2&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트만으로도 개발이 가능함에도 굳이 타입을 추가해야 하는 이유는&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자바스크립트의 태생적 한계&lt;/b&gt;와 &lt;b&gt;개발 환경의 변화&lt;/b&gt; 때문이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;자바스크립트의 태생적 한계:&lt;/b&gt; 초기 자바스크립트는 웹 브라우저의 간단한 상호작용을 위해 설계되어, 엄격함보다는 &lt;b&gt;유연함&lt;/b&gt;과 &lt;b&gt;간결함&lt;/b&gt;에 중점을 두었다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Node.js와 환경의 변화:&lt;/b&gt; Node.js의 등장으로 자바스크립트는 웹 서버, 모바일 앱 등 대규모 애플리케이션 개발에 사용되기 시작했다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유연함의 역설:&lt;/b&gt; 프로그램 규모가 커지자 자바스크립트의 '유연함'은 치명적인 단점이 되었다. 변수 타입이 엄격하지 않아 발생하는 버그가 시스템의 안정성을 위협했기 때문이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;✨ 타입스크립트는 자바스크립트의 고유한 매력은 유지하면서, &lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;대규모 애플리케이션 개발에 필수적인 안정성을 '타입'이라는 안전장치로 확보한 언어&lt;/b&gt;다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;br /&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inf.run/aGJcF&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765200162600&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&quot; data-og-description=&quot;현재 평점 5.0점 수강생 13,366명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://inf.run/aGJcF&quot; data-og-url=&quot;https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%ED%81%AC%EA%B8%B0-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bbxWKx/hyZOBTz8MH/vI92aWm5zF63PW1v0lOjSK/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/DbYB1/hyZO8QQpOL/GrrGF8g7usgyNEGJ2wHTjk/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/nPQYa/hyZOLomQxC/AObgz2swT95GdBDLnD7mlK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499&quot;&gt;&lt;a href=&quot;https://inf.run/aGJcF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inf.run/aGJcF&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bbxWKx/hyZOBTz8MH/vI92aWm5zF63PW1v0lOjSK/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/DbYB1/hyZO8QQpOL/GrrGF8g7usgyNEGJ2wHTjk/img.png?width=398&amp;amp;height=259&amp;amp;face=286_62_331_111,https://scrap.kakaocdn.net/dn/nPQYa/hyZOLomQxC/AObgz2swT95GdBDLnD7mlK/img.png?width=960&amp;amp;height=751&amp;amp;face=214_216_880_499');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;한 입 크기로 잘라먹는 타입스크립트(TypeScript)| 이정환 Winterlood - 인프런 강의&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;현재 평점 5.0점 수강생 13,366명인 강의를 만나보세요. 문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사 &lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  TypeScript</category>
      <category>typescript</category>
      <category>타입스크립트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/520</guid>
      <comments>https://recordoftheday.tistory.com/entry/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%86%8C%EA%B0%9C#entry520comment</comments>
      <pubDate>Mon, 8 Dec 2025 22:23:44 +0900</pubDate>
    </item>
    <item>
      <title> 자바스크립트 치트시트 (반복 메서드 추가!)  </title>
      <link>https://recordoftheday.tistory.com/entry/%F0%9F%93%8C%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8%F0%9F%93%8C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;split (자르기)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;텍스트를 구분자를 기준으로 분리해 배열에 담아 변환&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구분자&lt;/b&gt;에는 &lt;u&gt;문자열&lt;/u&gt; 가능, &lt;u&gt;RegExp객체&lt;/u&gt;도 가능(&lt;i&gt;But&lt;/i&gt; 문자열을 정규표현식으로 간주하지 않음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵션인 &lt;b&gt;두번째 매개변수&lt;/b&gt;는 반환 받을 배열의 크기를 지정하는 숫자&lt;/p&gt;
&lt;pre id=&quot;code_1764345030880&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let colorText = &quot;red, blue. green, yello&quot;;
let colors1 = colorText.split(&quot;,&quot;); // [&quot;red&quot;, &quot;blue&quot;, &quot;green&quot;, &quot;yellow&quot;];
let colors2 = colorText.split(&quot;,&quot;, 2); //[&quot;red&quot;, &quot;blue&quot;];
let colors3 = colorText.split(&quot;[^\,]; // [&quot;&quot;,&quot;,&quot;,&quot;,',&quot;,&quot;,&quot;&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*split() 메서드 내의 정규 표현식 지원은 브라우저마다 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;span style=&quot;background-color: #f6e199;&quot;&gt;보통 문자열을 자를때 split(',') 처럼 구분자를 하나만 사용한다. 그러나 쉼표(,)와 콜론(:) 두가지를 사용할 경우 어떻게 작성해야할까?&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764345279345&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const answer = &quot;1,2:3&quot;;
const result = answer.split(/[,:]/); 

console.log(result); // [&quot;1&quot;, &quot;2&quot;, &quot;3&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. / ... / (정규 표현식 선언): 자바스크립트에서는 정규표현식 패턴이야라고 알려주는 것임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. [ ... ]: 대괄호는 OR(또는)을 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;=&amp;gt; [,:] 라고 쓰면 &quot;&lt;b&gt;쉼표(,)이거나 콜론(:)이면 잘라라&lt;/b&gt;&quot;라는 뜻&lt;/u&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문자열 조작 메서드: concat()&lt;/h2&gt;
&lt;pre id=&quot;code_1764345628299&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let striingValue = &quot;hello &quot;;
let result = stringValue.concat(&quot;world&quot;);
alert(result); // &quot;hello world&quot;
alert(stringValue); // &quot;hello&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;concat() 메서드가 받는 매개변수 숫자에는&amp;nbsp;&lt;b&gt;제한 x, 문자열을 원하는 만큼 넘길 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764345742405&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let stringValue = &quot;hello &quot;;
let result = stringValue.concat(&quot;world&quot;, &quot;!&quot;);
alert(result); // &quot;hello world!&quot;
alert(stringValue); // &quot;hello&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;concat() 메서드는&amp;nbsp;&lt;b&gt;문자열을 합치는 목적&lt;/b&gt;, &lt;u&gt;+연산자가 여러 문자열을 합칠때는 더 빠르게 동작&lt;/u&gt;&lt;u&gt;&lt;/u&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;문자열 조작 메서드: &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;slice()&lt;/span&gt;, &lt;span style=&quot;background-color: #9feec3;&quot;&gt;substr()&lt;/span&gt;, &lt;span style=&quot;background-color: #99cefa;&quot;&gt;substring()&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;slice&lt;/b&gt;&lt;/span&gt;(어디서 부터 가져올지, &lt;u&gt;어디까지 가져올지&lt;/u&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt; substr&lt;/b&gt;&lt;/span&gt;(어디서 부터 가져올지, 어디까지 가져올지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt; substring&lt;/b&gt;&lt;/span&gt;(어디서 부터 가져올지, &lt;u&gt;어디까지 가져올지&lt;/u&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;slice()&lt;/b&gt;&lt;/span&gt;와 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;substring()&lt;/b&gt;&lt;/span&gt;에서는 두번째 매개변수가 가져오기를 끝내는 위치 바로 다음(&lt;b&gt;그 위치 직전까지의 문자는 가져오고 해당 위치의 문자는 가져오지 않음&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;substr()&lt;/b&gt;&lt;/span&gt;에서는 &lt;b&gt;두번째 매개변수가 문자 몇개&lt;/b&gt;를 가져올지 나타냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 메서드 모두 두번째 메서드 생략시, 문자열 전체 길이가 기본값으로 사용됨&lt;/p&gt;
&lt;pre id=&quot;code_1764346292626&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let stringValue = &quot;hello world&quot;;

alert(stringValue.slice(3)); // &quot;lo world&quot;
alert(stringValue.substring(3)); // &quot;lo world&quot;
alert(stringValue.substr(3)); // &quot;lo world&quot;

alert(stringValue.slice(3, 7); // &quot;lo, w&quot;
alert(stringValue.substring(3, 7); // &quot;lo w&quot;
alert(stringValue.substr(3, 7); // &quot;lo worl&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문자열 위치 메서드:&lt;span style=&quot;background-color: #ffc9af;&quot;&gt; indexOf()&lt;/span&gt;, &lt;span style=&quot;background-color: #99cefa;&quot;&gt;lastIndexOf() &lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열안에서 원하는 문자열의 위치를 찾는 메서드: indexOf(), lastIndexOf()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;indexOf(), lastIndexOf()는 모두 매개변수로 넘긴 문자열을 검색해 &lt;b&gt;그 위치를 반환하며 찾지 못할때 -1 반환&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;indexOf()&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 처음에서 검색을 시작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;lastIndexOf()&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 마지막에서 검색 시작&lt;/p&gt;
&lt;pre id=&quot;code_1764346561059&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let stringValue = &quot;hello world&quot;;
alert(stringValue.indexOf(&quot;o&quot;)); // 4
alert(stringValue.lastIndexOf(&quot;o&quot;))'; // 7&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;indexOf()&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;두번째 매개변수 보다 앞에 있는 문자는 전부 무시하고 해당 위치부터 문자열 마지막까지 검색&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;indexOf(&quot;o&quot;, 6) : 앞을 보세요! (Forward)&lt;/h4&gt;
&lt;blockquote data-path-to-node=&quot;9&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;9,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;명령:&lt;/b&gt; &quot;6번(w) 위치에 서서, &lt;b&gt;오른쪽(끝)을 보며&lt;/b&gt; o를 찾아라.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;출발:&lt;/b&gt; 6번(w)에 섬.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탐색:&lt;/b&gt; 오른쪽으로 고개를 돌림.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;6번(w): 아님.&lt;/li&gt;
&lt;li&gt;7번(o): &lt;b&gt;&quot;찾았다!&quot;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과:&lt;/b&gt; 찾은 위치인 &lt;b&gt;7&lt;/b&gt;을 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심:&lt;/b&gt; 6번 앞에 있는 hello (0~5번)는 &lt;b&gt;안 보임(무시)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;lastIndexOf()&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;두번째 매개변수보다 뒤에 있는 문자는 전부 무시하고 해당 위치부터 문자열 처음까지 검색&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;lastIndexOf(&quot;o&quot;, 6) : 뒤를 보세요! (Backward)&lt;/h4&gt;
&lt;blockquote data-path-to-node=&quot;14&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;14,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;명령:&lt;/b&gt; &quot;6번(w) 위치에 서서, &lt;b&gt;왼쪽(처음)을 보며&lt;/b&gt; o를 찾아라.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;15&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;출발:&lt;/b&gt; 6번(w)에 섬&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탐색:&lt;/b&gt; 왼쪽으로 고개를 돌려 뒤져봄
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;15,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;6번(w): 아님&lt;/li&gt;
&lt;li&gt;5번( ): 아님&lt;/li&gt;
&lt;li&gt;4번(o): &lt;b&gt;&quot;찾았다!&quot;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과:&lt;/b&gt; 찾은 위치인 4를 반환합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심:&lt;/b&gt; 6번 뒤에 있는 orld (7~10번)는 &lt;b&gt;안 보임(무시).&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1764346695227&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let stringValue = &quot;hello world&quot;; 
alert(stringValue.indexOf(&quot;o&quot;, 6); // 7
alert(stringValue.lastIndexOf(&quot;o&quot;, 6); // 4&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1764346902410&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;글자:  h  e  l  l  o     w  o  r  l  d
번호:  0  1  2  3  4  5  6  7  8  9  10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt; &lt;b&gt;indexOf()&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색을 시작하는 위치를 증가시키면서 indexOf()를 계속 호출 가능&lt;/p&gt;
&lt;pre id=&quot;code_1764347243151&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = &quot;banana&quot;;
const target = &quot;a&quot;; // 찾을 글자

let index = str.indexOf(target); // 1. 일단 첫 번째 'a'를 찾음

// 2. 찾은 게 없을 때(-1)까지 계속 반복 (while 문)
while (index !== -1) {
  console.log(`찾았다! 위치: ${index}`);

  // 3. 다음 검색은 &quot;방금 찾은 곳 + 1&quot;부터 시작
  // (만약 +1을 안 하면, 제자리에서 계속 똑같은 'a'만 찾습니다!)
  index = str.indexOf(target, index + 1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;startsWith (찾기)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;startsWith()메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 텍스트를 문자열 처음에서 찾을 수 있다면&amp;nbsp;&lt;b&gt;true&lt;/b&gt;를 반환&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;숫자 변환: &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;Number()&lt;/span&gt;, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;parseInt()&lt;/span&gt;, &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;parseFloat()&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;Number()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 데이터 타입에든 쓸 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매개변수로 불리언 값을 넘겼다면 true와 false를 각각 1과 0으로 바꿔 반환&lt;/li&gt;
&lt;li&gt;매개변수로 숫자로 넘겼다면 그대로 반환&lt;/li&gt;
&lt;li&gt;매개변수로 undefiined를 넘겼다면 NaN을 반환&lt;/li&gt;
&lt;li&gt;매개변수로 문자열을 넘겼다면
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문자열이 숫자로 구성되어 있으면 &quot;1&quot;&amp;nbsp;&amp;rarr; 1, &quot;123&quot;&amp;nbsp;&amp;rarr; 123, &quot;011&quot;&amp;rarr; 11 (문자열 맨 앞에 +, - 기호 있으면 유지)&lt;/li&gt;
&lt;li&gt;문자열 &quot;1.1&quot;같은 유효한 부동소수점 숫자 형식이면 해당하는 부동소수점 숫자를 반환, 리딩 소수(0이 아닌 첫 수자 앞의 0전부: 01, 02 etc)는 버림&lt;/li&gt;
&lt;li&gt;문자열이 &quot;oxf&quot;같은 유효한 16진수 형식이면 그에 해당하는 정수를 반환&lt;/li&gt;
&lt;li&gt;빈문자열은 0 반환&lt;/li&gt;
&lt;li&gt;위의 형식에 맞지 않는 문자열이면 NaN을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;객체를 넘기면 먼저 valueOf()메서드를 호출하고 그 반환 값에 앞에서 설명한 규칙 적용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과가 NaN이면 toString() 메서드를 호출한 후 문자열 변환 규칙 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1764409131510&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let num1 = Number(&quot;Hello Wrold&quot;); // NaN
let num2 = Number(&quot;&quot;); // 0
let num3 = Number(&quot;000011)&quot;; // 11 (리딩제로 버림)
let num4 - Number(true); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Number 함수로 문자열 &amp;rarr; 숫자로 바꾸려면 복잡하고 이상한 규칙 기억해야함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;parseInt()&lt;/span&gt;, &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;parseFloat()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 두 함수는 문자열을 숫자로 바꾸는 용도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; color: #333333; text-align: start;&quot;&gt;parseInt() &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr; 정수 형태의 문자열을 숫자로 바꿀 때&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리딩 스페이스 전부 버림&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1764409517983&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let num1 = parseInt(&quot;1234blue&quot;); //1234
let num2 = parseInt(&quot;&quot;&quot;&quot;); // NaN
let num3 = parseInt(&quot;0xA&quot;); // 16진수 10
let num4 = parseInt(22.5); // 22
let num5 = parseInt(&quot;70&quot;); .. 70
let num6 = parseInt(&quot;0xf&quot;); 16진수 15&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9; color: #333333; text-align: start;&quot;&gt;parseFloat()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0번째 위치부터 각 문자를 변환한다. (&lt;span style=&quot;background-color: #f6e199;&quot;&gt;parseInt()&lt;/span&gt;도 그렇게함)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문자열에서 잘못된 부동소수점 숫자를 만날때까지 파싱을 계속한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 첫번째 소수점은 유효, 두번째 소수점은 잘못된 문자로 간주해 그 이후의 문자열 무시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &quot;22.34.5&quot; 는 22.34로 반환&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리딩 제로를 항상 무시&lt;/li&gt;
&lt;li&gt;15진수를 넘기면 항상 0을 반환&lt;/li&gt;
&lt;li&gt;문자열이 전체 숫자(소수점이 없거나 소수점 뒤에 0만 있는 형식)인 경우 parseFloat()는 정수 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1764409713330&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let num1 = parseFloat(&quot;1234blue&quot;); //1234
let num2 = parseFloat(&quot;0xA&quot;); // 16진수 10
let num3 = parseFloat(22.5); // 22.5
let num4 = parseFloat(&quot;22.34.5&quot;); // 22.34
let num5 = parseFloat(&quot;0908.5&quot;); // 908.5
let num6 = parseFloat(&quot;3.125e7&quot;); // 3125000&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;반복 메서드: &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;every()&lt;/span&gt;, &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;filter()&lt;/span&gt;, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;forEach()&lt;/span&gt;, &lt;span style=&quot;background-color: #9feec3;&quot;&gt;map()&lt;/span&gt;,&lt;span style=&quot;background-color: #99cefa;&quot;&gt; some()&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;every()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 모든 데이터에서 콜백 함수를 호출하고 반환 값이 전부 true이면 true를 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;filter()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 모든 데이터에서 콜백 함수를 호출하고 반환 값이 전부 true인 데이터를 새 배열에 저장해 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;forEach()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 모든 데이터에서 콜백 함수를 호출. 이 메서드는 반환값 x&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;map()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 모든 데이터에서 콜백 함수를 호출하고 그 결과를 새 배열에 저장해 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;some()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 모든 데이터에서 콜백 함수를 호출하고 반환 값 중 하나라도 true이면 true 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 메서드들은 원래 배열에 들어있던 데이터를 바꾸지x&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;evey()&lt;/span&gt;와 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;some()&lt;/span&gt; 메서드는 원래 배열의 데이터를 특정 조건에 따라 쿼리한다는 점이 비슷&lt;/p&gt;
&lt;pre id=&quot;code_1764599934059&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

// every
let everyResult = numbers.every(function(item, index, array) {
	return (item&amp;gt;2);
}));

console.log(everyResult); // false

// some
let someResult = numbers.some(function(item, index, array) {
	return (item&amp;gt;2);
}));

console.log(someResult); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 중 2를 초과하는 것은 일부에 불과하므로 every()는 false, some()은 true&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;filter()&lt;/span&gt;는 콜백 함수의 결과에 따라 해당 데이터를 반환 배열에 포함할지 결정&lt;/p&gt;
&lt;pre id=&quot;code_1764600041902&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

// filter
let filterResult = numbers.filter(function(item, index, array) {
	return (item&amp;gt;2);
}));

console.log(filterResult); // [3, 4, 5, 4, 3]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;filter()&lt;/span&gt; 메서드는 배열에서 특정 조건에 맞는 데이터만 쿼리할때 유용!&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;map()&lt;/span&gt;도 배열 반환, 결과 배열의 각 데이터는 원래 배열에서 해당 위치에 있던 데이터를 콜백 함수에 넘긴 결과&lt;/p&gt;
&lt;pre id=&quot;code_1764600153543&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

// map
let mapResult = numbers.map(function(item, index, array) {
	return item * 2;
}));

console.log(mapResult); // [2, 4, 6, 8, 10, 8, 6, 4, 2];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;map() 메서드는 원래 배열과 1:1로 대응하는 배열을 만들때 유용&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;forEach()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;단순히 배열의 각 데이터에서 콜백 함수를 실행, 반환 값이&amp;nbsp;&lt;b&gt;없으며&lt;/b&gt; 기본적으로 해당 배열에서 for문을 실행하는 것과 마찬가지&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764600336354&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

// forEach
numbers.forEach(function(item, index, array){
	//코드
});&lt;/code&gt;&lt;/pre&gt;</description>
      <category>  JavaScript</category>
      <category>내입맛대로정리</category>
      <category>자바스크립트</category>
      <category>치트시트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/518</guid>
      <comments>https://recordoftheday.tistory.com/entry/%F0%9F%93%8C%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%B9%98%ED%8A%B8%EC%8B%9C%ED%8A%B8%F0%9F%93%8C#entry518comment</comments>
      <pubDate>Mon, 1 Dec 2025 23:46:22 +0900</pubDate>
    </item>
    <item>
      <title>[자바스크립트] 객체 지행 프로그래밍</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%89-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체지향언어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티와 메서드를 가지는 객체를 여러개 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티와 메서드는 이름으로 구별하며 값에 대응한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 이름-값쌍의 그룹&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 값은 테이터나 함수가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 객체는 참조 타입을 바탕으로 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체를 이해해보자&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;객체를 만드는 가장 단순한 방법&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;Object의 인스턴스를 만들고 프로퍼티와 메서드를 추가하는 방법&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764381513778&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = new Object();
person.name = &quot;Nicholas&quot;;
person.age  = 29l
person.job = &quot;Software Engineer&quot;;

person.sayName = function() {
	alert(this.name);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체&lt;/b&gt;: person&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name, age,&amp;nbsp; job =&amp;gt; &lt;b&gt;3가지 프로퍼티&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sayName() =&amp;gt; &lt;b&gt;메서드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sayName() 메서드는 this.name =&amp;gt; 즉,&lt;u&gt; person.name의 값을 표시&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;객체 리터럴 패턴&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1764386940667&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
	name: &quot;Nicholas&quot;,
	age: 29,
	job: &quot;Software Engineer&quot;,

	sayName:function() {
	alert(this.name);
	}
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로퍼티 타입&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 프로퍼티&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 값에 대한 단 하나의 위치를 포함해 이 위치에서 값을 읽고 쓴다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;[[Configurable]] - 해당 프로퍼티가 delete를 통해 삭제하거나, 프로퍼티의 속성을 바꾸거나, 접근자 프로퍼티로 변할 수 있음(객체에서 직접 정의한 모든 프로퍼티에서 이 속성은 기본적으로 true)&lt;/li&gt;
&lt;li&gt;[[Enumerable]] - for-in 루프에서 해당 프로퍼티를 반환 (객체에서 직접 정의한 모든 프로퍼티에서 이 속성은 기본적으로 true)&lt;/li&gt;
&lt;li&gt;[[Wirtable]] - 프로퍼티의 값을 바꿀 수 있음 (객체에서 직접 정의한 모든 프로퍼티에서 이 속성은 기본적으로 true)&lt;/li&gt;
&lt;li&gt;[[Value]] - 프로퍼티의 실제 데이터 값을 포함, 프로퍼티의 값을 읽는 위치이며 새로운 값을 쓰는 위치 (속성의 기본값은 undefined)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Property()메서드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티를 추가하거나 수정할 객체, 프로퍼티, 서술자 객체&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3가지를 매개변수로 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서술자 객체의 프로퍼티는 내부 속성 이르모가 1:1로 대응&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; configurable, enumerable, wirtable, value&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 값의 일부 또는 전부를 바꿔 대응하는 속성 값을 바꿀 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1764387490882&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person ={};
Obejct.defineProperty(person, &quot;name&quot;, {
	writeable: false,
    value: &quot;Nichoals&quot;
});

alert(person.name); // &quot;Nicholas&quot;
person.name = &quot;Greg&quot;;
alert(person.name); // &quot;Nicholas&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로퍼티의 값은 바꿀 수 없으며, 새로운 값을 할당하려 시도하면 스트릭트 모드가 아닐때 무시되고 스트릭트 모드에서는 에러 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object.defineProperty()를 호출할때&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;configuable이나 enumerable, writable의 값을 따로 명시하지 않으면 기본 값은 false&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;접근자 프로퍼티&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터값이 없는 대신 &lt;u&gt;getter함수와 setter 함수로 구성&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;getter함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접급자 프로퍼티를 읽을때 getter 함수가 호출되며 유효한 값을 반환할 책임이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근자 프로퍼티에 쓰기 작업을 할때,&amp;nbsp;새로운 값과 함께 함수를 호출하며 이 함수가 데이터를 어떻게 사용할지 결정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;접근자 프로퍼티의 4가지 속성&lt;/u&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;[[Configurable]] - 해당 프로퍼티가 delete를 통해 삭제되거나, 프로퍼티의 속성을 바꿀 수 있거나, 데이터 프로퍼티로 바꿀 수 있음 (객체에서 직접 정의한 모든 프로퍼티에서 이 속성은 기본적으로 true)&lt;/li&gt;
&lt;li&gt;[[Enumerable]] - for...in 루프에서 해당 프로퍼티를 반환함 (객체에서 직접 정의한 모든 프로퍼티에서 이 속성은 기본적으로 true)&lt;/li&gt;
&lt;li&gt;[[Get]] - 프로퍼티를 읽을 때 호출할 함수 (기본값은 undefined)&lt;/li&gt;
&lt;li&gt;[[Set]] - 프로퍼티를 바꿀 때 호출할 함수 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;(기본값은 undefined)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근자 프로퍼티를 명시적으로 정의할 수 없다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반드시 Object.defineProperty()를 써야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1764388268735&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let book = {
	_year: 2004,
    edition: 1
};

Object.defineProperty(book, &quot;year&quot;, {
	get: function() {
    	return this._year;
    },
    set: function(newValue) {
    	if(newValue &amp;gt; 2004) {
        	this._year = newValue;
            this.editioin += newValue - 2004;
        }
    }
});

book.year = 2005;
alert(book.edition); //2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체: book&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티: _year, edition&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;_yeaer의 언더바(_)는 이 프로퍼티는 객체의 메서드를 통해서만 접근할 것이고 객체 외부에서는 접근하지 않겠다는 의도를 나타낸것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;year프로퍼티는 접근자 프로퍼티로 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getter함수는 단순히 _year의 값을 반환하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setter 함수는 올바른 edition을 반환하기 위해 계산을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; year프로퍼티를 2005로 고치면 edition은 2가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getter와 setter는 꼭 지정x&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getter함수만 저장하면 해당 프로퍼티는 읽기 전용, 이 프로퍼티를 수정하려는 시도는 모두 무시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트릭트 모드에서는 getter 함수만 지정된 프로퍼티를 수정하려할때 에러 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setter 함수만 지정된 프로퍼티를 읽으려하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트릭트 모드가 아닐 때는 undefined를 반환하며 스트릭트 모드에서 에러 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;다중 프로퍼티&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Object.defineProperties() 메서드 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서술자를 이용해 여러 프로퍼티를 한 번에 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수는 프로퍼티를 추가하거나 수정할 객체,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 프로퍼티 이름이 추가 및 수정할 프로퍼티 이름과 대응하는 객체 2가지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반환 값은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근자 프로퍼티에서는 configure, enumerable, get, set을 프로퍼티로 포함하는 객체를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 프로퍼티에서는 configure, enumerable, writable, value를 프로퍼티로 포함하는 객체를 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  JavaScript/JavaScript</category>
      <category>다중프로퍼티</category>
      <category>자바스크립트</category>
      <category>프로퍼티</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/519</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%89-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D#entry519comment</comments>
      <pubDate>Sat, 29 Nov 2025 12:58:37 +0900</pubDate>
    </item>
    <item>
      <title>try-catch문</title>
      <link>https://recordoftheday.tistory.com/entry/try-catch%EB%AC%B8</link>
      <description>&lt;pre id=&quot;code_1764332998090&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
 // 에러가 생길 수 있는 코드
} catch (error) {
 // 에러가 생겼을 때 할일
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfgGNE/dJMcafLOH6J/GaQkWTjxLB88I0d4BRXYik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfgGNE/dJMcafLOH6J/GaQkWTjxLB88I0d4BRXYik/img.png&quot; data-alt=&quot;https://ko.javascript.info/try-catch&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfgGNE/dJMcafLOH6J/GaQkWTjxLB88I0d4BRXYik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfgGNE%2FdJMcafLOH6J%2FGaQkWTjxLB88I0d4BRXYik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;375&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://ko.javascript.info/try-catch&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;try절에서 에러가 생기면 코드 실행을 즉시 멈추고 catch 절을 실행&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;catch 절은 에러에 대한 정보를 담은 객체를 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;finally 절&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;try-catch는 옵션으로 finally절 사용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;finally절의 코드는 항상 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 없어도, catch절을 실행하더라도 finally절은 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에러 반환&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;try catch문의 throw연산자는 언제든 커스텀 에러를 반환 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;throw 연산자에는 반드시 값이 필요하지만 값의 타입에는 제한이 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1764332200690&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;throw 12345;
throw &quot;Hello World&quot;;
throw true;
throw {name:&quot;JavaScript&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;try 연산자를 사용하면 코드 실행은 즉시 멈추며 try-catch문에서 해당 값을 받았을 때만 계속 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 반환하는 에러(TypeError, Refference Error 등)는 내장된 에러 타입을 통해 정확히 시뮬레이트를 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각 에러 타입의 생성자는 매개변수로 에러 메시지 단 하나만 받는다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764332313759&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;throw new Error(&quot;Something bad happend&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커스텀 에러 메시지와 함께 범용 에러를 발생시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 이 에러를 마치 자신이 발생시킨 것처럼 처리하되 표시하는 메시지만 커스텀 에러 메시지로 바꾼다.&lt;/p&gt;
&lt;pre id=&quot;code_1764332389520&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;throw new SyntaxError(&quot;문법이 좀 이상합니다.&quot;);
throw new TypeError(&quot;변수 타입을 착각한거 아닌가요?);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커스텀 에러 메시지가 필요할 때 쓰이는 에러 타입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;Error, RangeError, ReferenceError, TypeError&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;커스텀 에러 vs try-catch문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;try-catch문&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 에러를 기본 방식대로 처리하지 못하게 막는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;커스텀 에러&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 일어난 이류를 제공하는 것&lt;/p&gt;</description>
      <category>  JavaScript/JavaScript</category>
      <category>catch</category>
      <category>TRY</category>
      <category>try-catch</category>
      <category>TRYCATCH</category>
      <category>에러</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/517</guid>
      <comments>https://recordoftheday.tistory.com/entry/try-catch%EB%AC%B8#entry517comment</comments>
      <pubDate>Fri, 28 Nov 2025 21:29:47 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5 주차 | TiTaS 프로젝트를 마치며: 결과 공유</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-TiTaS-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%A7%88%EC%B9%98%EB%A9%B0-%EA%B2%B0%EA%B3%BC-%EA%B3%B5%EC%9C%A0</link>
      <description>&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트 주제를 두고 고민하던 중, 거창한 목표를 세우기보다 &quot;우선 내 주변에서 아이디어를 찾아보자&quot;는 생각으로 시작했다. 그렇게 &quot;내가 필요한 걸 직접 만든다&quot;는 단순하지만 확실한 동기가 TiTaS 프로젝트의 출발점이 되었다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;이 프로젝트는 단순한 기능 구현을 넘어 나를 엔지니어로 한 단계 성장시켰다. 기술적으로는 React의 상태 관리 구조를 심층적으로 분석하고, 다양한 브라우저 API를 서비스 환경에 맞게 최적화하는 경험을 쌓았다. 또한, 개발자 관점을 넘어 사용자를 배려하는 UX/UI 설계의 중요성을 몸소 체감했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;무엇보다 가장 큰 수확은 태도의 변화다. 기술적 제약 앞에서 '안 되는 이유'를 찾기보다, 어떻게든 '되게 하는 방법'을 찾아내는 집요한 엔지니어링 마인드셋을 갖추게 되었다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;TiTaS v1.0 개발은 여기서 마침표를 찍지만, 더 나은 v2.0을 향한 커밋은 계속될 것이다. 긴 개발 일지를 읽어준 모든 분께 감사하며, 치열한 고민의 결과물을 공유한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TiTaS 프로젝트 보러 가기&lt;/h2&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;백문이 불여일견, 직접 만든 나만의 영어 훈련장 TiTaS를 아래 링크에서 경험할 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배포링크&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tikitaka-script.vercel.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tikitaka-script.vercel.app/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763810826698&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;TiTaS - TikiTaka Script&quot; data-og-description=&quot;대화 연습을 위한 스크립트 작성 및 연습 플랫폼.&quot; data-og-host=&quot;tikitaka-script.vercel.app&quot; data-og-source-url=&quot;https://tikitaka-script.vercel.app/&quot; data-og-url=&quot;https://tikitaka-script.vercel.app&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/boOK23/hyZNDxeXyD/wI9GNHL9mc8NbKSBme0psK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://tikitaka-script.vercel.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://tikitaka-script.vercel.app/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/boOK23/hyZNDxeXyD/wI9GNHL9mc8NbKSBme0psK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;TiTaS - TikiTaka Script&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;대화 연습을 위한 스크립트 작성 및 연습 플랫폼.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;tikitaka-script.vercel.app&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;소스 코드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;[GitHub 저장소 링크]&quot; href=&quot;https://github.com/yshls/titas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; [GitHub 저장소 링크]&lt;/a&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size26&quot;&gt;TiTaS v2.0: 언젠가 이루고 싶은 도전들&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;1) 데이터 영속성 및 동기화: LocalStorage &amp;rarr; DB (Supabase/Firebase)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[ 현재 ] 현재는 모든 데이터가 브라우저의 localStorage에 저장된다. 구현은 간편하지만, 캐시 삭제 시 데이터가 휘발되거나 기기 간 연동이 불가능하다는 치명적인 단점이 있다.&lt;/li&gt;
&lt;li&gt;[ &lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;목표&lt;/span&gt; ] 서버와 데이터베이스 도입을 통해 데이터 안정성을 확보하고 싶다. 구축 비용과 리소스를 고려해 Supabase나 Firebase&amp;nbsp;도입을 염두에 두고 있다. 만약 구현된다면, PC에서 작성한 스크립트를 모바일에서도 끊김 없이 연습하는 '크로스 플랫폼' 환경을 경험해 볼 수 있을 것이다!!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;2) 음성 인식 고도화: Web Speech API &amp;rarr; OpenAI Whisper&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[ &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;현재&lt;span&gt; &lt;/span&gt;&lt;/span&gt;] 무료로 사용할 수 있는 브라우저 내장 Web Speech API를 사용 중이다. 속도는 빠르지만 인식률이 불안정하고, 발음의 미세한 뉘앙스까지 잡아내기엔 한계가 있다.&lt;/li&gt;
&lt;li&gt;[ &lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;목표&lt;/span&gt; ] 현존하는 가장 강력한 음성 인식 모델인 OpenAI Whisper API 연동을 고려하고 있다. 단순한 텍스트 변환(STT)을 넘어, 사용자의 억양과 발음 정확도까지 분석해 주는 AI 코칭 피드백 시스템을 만들어본다면 꽤 흥미로운 작업이 될 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;3) 콘텐츠 생성 자동화: Generative AI 활용&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[ &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;현재&lt;span&gt; &lt;/span&gt;&lt;/span&gt;] 사용자가 학습할 대본을 직접 입력해야 한다. 능동적인 학습에는 좋지만, 초기 데이터 입력 과정이 사용자에게 번거로운 진입 장벽이 될 수 있다.&lt;/li&gt;
&lt;li&gt;[ &lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;목표&lt;/span&gt; ] ChatGPT API를 연동해 콘텐츠 생산성을 높이는 기능을 구상 중이다. 예컨대 &quot;공항 입국 심사 상황을 만들어줘&quot;라고 요청하면, TiTaS 포맷에 맞는 롤플레잉 대본을 AI가 자동으로 생성해 주는 기능이 추가된다면 훨씬 편리하지 않을까?&lt;/li&gt;
&lt;/ul&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/515</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-TiTaS-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%A7%88%EC%B9%98%EB%A9%B0-%EA%B2%B0%EA%B3%BC-%EA%B3%B5%EC%9C%A0#entry515comment</comments>
      <pubDate>Sat, 22 Nov 2025 20:41:59 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5 주차 | [디자인 스토리] TiTaS의 얼굴과 색상의 여정</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EB%94%94%EC%9E%90%EC%9D%B8-%EC%8A%A4%ED%86%A0%EB%A6%AC-TiTaS%EC%9D%98-%EC%96%BC%EA%B5%B4%EA%B3%BC-%EC%83%89%EC%83%81%EC%9D%98-%EC%97%AC%EC%A0%95</link>
      <description>&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;기능 구현과 버그 수정이라는 긴 터널을 지나고 나니, 문득 화면이 눈에 들어왔다. 기능은 완벽하게 돌아가는데, 어딘가 투박하고 정돈되지 않은 느낌. 마치 골조만 올라간 건물 같았다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;사용자가 서비스를 처음 마주했을 때 &quot;써보고 싶다&quot;는 느낌을 받으려면, 탄탄한 코딩만큼이나 직관적인 디자인과 명확한 정체성이 필요하다. 이번 글은 TiTaS가 '돌아가는 코드 덩어리'에서 하나의 '그럴듯한 제품'으로 변모하는 과정에 대한 기록이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;1. 얼굴 짓기: TiTaS로고&lt;/h2&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;Tiki-Taka Script이기에 상대방과 대화하는 느낌이 먼저 떠올랐다. 이름(TiTaS) 속에 알파벳 'T'가 두 번 들어간다는 점에 착안하여, 두 개의 'T'가 서로 마주 보고 대화하는 모습을 형상화했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmF9EM/dJMcaaX0zqs/lfBzzVO1ZhGPFdEkfpmJRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmF9EM/dJMcaaX0zqs/lfBzzVO1ZhGPFdEkfpmJRk/img.png&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;2048&quot; data-is-animation=&quot;false&quot; width=&quot;301&quot; height=&quot;301&quot; data-widthpercent=&quot;42.84&quot; style=&quot;width: 42.3444%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmF9EM/dJMcaaX0zqs/lfBzzVO1ZhGPFdEkfpmJRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmF9EM%2FdJMcaaX0zqs%2FlfBzzVO1ZhGPFdEkfpmJRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2048&quot; height=&quot;2048&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIauT1/dJMcacarWLJ/ktXMELaAp1d3fzxTUWs8nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIauT1/dJMcacarWLJ/ktXMELaAp1d3fzxTUWs8nk/img.png&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;419&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.4928%;&quot; data-widthpercent=&quot;57.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIauT1/dJMcacarWLJ/ktXMELaAp1d3fzxTUWs8nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIauT1%2FdJMcacarWLJ%2FktXMELaAp1d3fzxTUWs8nk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;559&quot; height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. UI 변천사: 사용성을 찾아가는 여정&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;780&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OoFrl/dJMcacVO8hl/6XUtPR6pC8cbsjkM0g9AL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OoFrl/dJMcacVO8hl/6XUtPR6pC8cbsjkM0g9AL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OoFrl/dJMcacVO8hl/6XUtPR6pC8cbsjkM0g9AL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOoFrl%2FdJMcacVO8hl%2F6XUtPR6pC8cbsjkM0g9AL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;408&quot; height=&quot;593&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;780&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 디자인은 그저 기능을 배치하는 데 급급했다. 버튼은 투박했고, 색상은 통일감이 없었으며, 정보의 위계가 불분명했다. 처음엔 가장 무난한 Blue 계열로 색상을 입혀보았다. 하지만 막상 적용해 보니 서비스만의 개성이 느껴지지 않고, 시중의 흔한 관리자 페이지처럼 딱딱해 보여 아쉬움이 남았다. 참고로 디자인은 어느정도 피그마에 틀만 만들어두고 기능구현을 하면서 디자인을 동시에 만들기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 첫번째 시도: 코랄과 두꺼운 선&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 '티키타카'라는 단어에서 오는 경쾌함을 표현하고 싶었다. 그래서 과감한 코랄색상을 메인으로 잡고, UI 요소들의 테두리를 두껍게 처리했다. 지금보니 장난스러운 메모장같은 느낌이 든다. (하지만 border-3는 정말 맘에 든다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deKNL0/dJMcahpiHgQ/2LrLt81O76mx1y2GE6z1v1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deKNL0/dJMcahpiHgQ/2LrLt81O76mx1y2GE6z1v1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deKNL0/dJMcahpiHgQ/2LrLt81O76mx1y2GE6z1v1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeKNL0%2FdJMcahpiHgQ%2F2LrLt81O76mx1y2GE6z1v1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1856&quot; height=&quot;902&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 차분한 블루와 스케치북 감성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;그럼 눈을 좀 식혀줄까?&quot; 코랄의 쨍함을 덜어내기 위해 선택한 것은 뮤트한 블루였다. 여기에 두꺼운 검은 테두리와 둥글둥글한 폰트를 유지해, 마치 나만의 영어 낙서 같은 편안하고 캐주얼한 느낌을 주려 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-19 225530.png&quot; data-origin-width=&quot;1880&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/24ioU/dJMcafkIcp8/Gfgp5xA1Ry7KTIM4LcG571/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/24ioU/dJMcafkIcp8/Gfgp5xA1Ry7KTIM4LcG571/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/24ioU/dJMcafkIcp8/Gfgp5xA1Ry7KTIM4LcG571/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F24ioU%2FdJMcafkIcp8%2FGfgp5xA1Ry7KTIM4LcG571%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1880&quot; height=&quot;862&quot; data-filename=&quot;스크린샷 2025-11-19 225530.png&quot; data-origin-width=&quot;1880&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 방향 전환: 차분한 브라운&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;조금 더 진중하고 차분해지자.&quot; 두 번째 선택은 브라운이었다. 아이보리 배경과 가장 자연스럽게 어우러지는 흙의 색&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적인 톤이 차분해지니 눈이 확실히 편안해졌다. 하지만 이번엔 너무 칙칙해 보이는 게 문제였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(아쉽게도.. 캡처는 안해놨다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 밸런스 찾기: 브라운에 녹아드는 주황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라운의 차분함은 유지하되, 생기를 불어넣을 포인트가 필요했다. 그래서 브라운과 톤이 맞으면서도 에너지가 느껴지는 따뜻한 주황을 포인트 컬러로 정했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-21 004756.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buk0bq/dJMcabJn5lW/rABjuK9CnfExOV3TZKM5f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buk0bq/dJMcabJn5lW/rABjuK9CnfExOV3TZKM5f0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buk0bq/dJMcabJn5lW/rABjuK9CnfExOV3TZKM5f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbuk0bq%2FdJMcabJn5lW%2FrABjuK9CnfExOV3TZKM5f0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;499&quot; height=&quot;465&quot; data-filename=&quot;스크린샷 2025-11-21 004756.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 디테일의 완성: 선 두께 다이어트 (1px)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 거슬렸던 건 초기에 설정했던 '두꺼운 선'이었다. 색상은 세련되게 바뀌었는데, 선이 두꺼우니 여전히 장난감 같은 느낌이 남아있었다. 그렇다고 선을 아예 없애면 구획이 모호해졌다. 나는 선의 존재감은 남기되, 무게감은 덜어내기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 카드와 버튼의 테두리를 얇은 1px 실선으로 바꾸는 순간, 화면이 훨씬 넓어 보이고 정돈된 느낌으로 변했다. (궁금하면 배포링크 클릭해보기, 아마 다음다음 게시글에 배포링크 적을 예정이다.) 그렇게 지금의 TiTas디자인 시스템이 완성되었다.&lt;/p&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <category>TiTaS</category>
      <category>로고</category>
      <category>영어회화</category>
      <category>우테코</category>
      <category>프리코스</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/514</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EB%94%94%EC%9E%90%EC%9D%B8-%EC%8A%A4%ED%86%A0%EB%A6%AC-TiTaS%EC%9D%98-%EC%96%BC%EA%B5%B4%EA%B3%BC-%EC%83%89%EC%83%81%EC%9D%98-%EC%97%AC%EC%A0%95#entry514comment</comments>
      <pubDate>Sat, 22 Nov 2025 20:15:38 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5 주차 | 맞춤형 TTS, 결과 모달, 그리고 붕 떠버리는 Footer</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EB%A7%9E%EC%B6%A4%ED%98%95-TTS-%EA%B2%B0%EA%B3%BC-%EB%AA%A8%EB%8B%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%B6%95-%EB%96%A0%EB%B2%84%EB%A6%AC%EB%8A%94-Footer</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기능 구현과 배포를 마친후 이제는 사용성에 대해서 눈에 들어오기 시작했다. 잠깐 떴다 사라지는 토스트 메시지는 talkpage에서 결과를 확인하기에는 너무 가벼웠고, 기계적인 TTS 목소리는 몰입을 방해했다. 또한 URL을 보낼때 사진과 설명이 없는 주소는 너무 휑하게 느껴졌다.&amp;nbsp;2%의 아쉬움을 채우기 위해 UX와 디테일 기능을 추가했다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UX 개선: 토스트(Toast)는 결과창으로 적합하지 않다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;처음에는 연습이 끝났을 때 점수와 결과를 react-hot-toast로 가볍게 보여주었다. 하지만 토스트는 몇 초 뒤 스르륵 사라져 버린다는 치명적인 단점이 있었다. 사용자는 힘든 연습을 마친 후 자신의 성취(정확도, 소요 시간)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;진득하게 확인하고 싶어 한다.&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사라지는 메시지는 이런 성취감을 반감시켰다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;연습 종료 피드백을 결과 모달로 변경했다. 사용자가 확인 버튼을 누르기 전까지 결과 화면을 유지했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt; 기능 고도화: 듣고 싶은 목소리로, 듣고 싶은 문장 TTS 추가&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존 TTS는 컴퓨터 턴이 되면 자동으로 한 번재생이 되고 끝나는 수동적인 기능이었다. 하지만 언어 학습에서는 &quot;방금 그 문장 발음이 뭐였지? 다시 듣고 싶은데?&quot;의 니&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;즈가 분명 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;109&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vXD6i/dJMcahCPoXn/FAu1kEVXUnodwRU7FNfVik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vXD6i/dJMcahCPoXn/FAu1kEVXUnodwRU7FNfVik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vXD6i/dJMcahCPoXn/FAu1kEVXUnodwRU7FNfVik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvXD6i%2FdJMcahCPoXn%2FFAu1kEVXUnodwRU7FNfVik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;128&quot; height=&quot;109&quot; data-origin-width=&quot;128&quot; data-origin-height=&quot;109&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;Click to listen! &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;대화 말풍선을 클릭하면 해당 문장의 TTS가 즉시 다시 재생되는 기능을 추가해 사용자가 원하는 만큼 반복해 원어민 발음을 들을 수 있도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ehm32q/dJMcaiuVw2n/aijKlVPVfXm2nIqGzV2D2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ehm32q/dJMcaiuVw2n/aijKlVPVfXm2nIqGzV2D2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ehm32q/dJMcaiuVw2n/aijKlVPVfXm2nIqGzV2D2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fehm32q%2FdJMcaiuVw2n%2FaijKlVPVfXm2nIqGzV2D2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;314&quot; height=&quot;193&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Voice Selection&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;브라우저가 다양한 목소리 중 사용자가 원하는 발음을 선택할 수 있도록 추가했다. (영국 발음도 들을 수 있게된것이다!)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;물음표와 느낌표의 함정&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diff 엔진이 너무 엄격해서 생긴 문제였다. 사용자가 &quot;Hello&quot;라고 정확히 말했는데, 대본에 &quot;Hello!&quot;라고 적혀있다는 이유로 컴퓨터는 이를 틀린 문장으로 간주했다. 감정을 담은 문장 부호 때문에 발음 정확도가 깎이는 것은 억울한 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교 로직 전에 정규표현식(Regex)으로 문장 부호를 제거하는 전처리 과정을 강화해 이제 사용자가 감정을 담아 외치든, 담백하게 말하든 오직 '단어'의 정확성만으로 공정하게 채점한다. 덕분에 사용자는 문장 부호 신경 쓸 필요 없이 발화에만 집중할 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이아웃 좀비: 죽지 않는 Footer 이슈&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-21 184852.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FQyuO/dJMcag4ZFds/7gthnid5q1QMUwmI7zG2x0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FQyuO/dJMcag4ZFds/7gthnid5q1QMUwmI7zG2x0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FQyuO/dJMcag4ZFds/7gthnid5q1QMUwmI7zG2x0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFQyuO%2FdJMcag4ZFds%2F7gthnid5q1QMUwmI7zG2x0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;279&quot; data-filename=&quot;스크린샷 2025-11-21 184852.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반응형에서 Footer는 Outlet 중앙에 떠있는 현상이 발생했다. RootLayout에서 head랑 footer를 관리함으로 &lt;span&gt;RootLayout의 구조나 전역 스타일 문제인 줄 알고 padding, height, flex 설정 등을 이것저것 만지작거렸는데 아무리 고쳐도 footer가 이상하게 배치되거나 스크롤이 안 먹혔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한참동안 수정하고 삭제하고를 반복했다. 근데 CreatePage외 다른 페이지에서는 문제가 안되었기에 혹시 하고 CreatePage를 살펴봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고보니 CreatePage&lt;span&gt;의 최상위 div에 h-screen과 gap-4 클래스가 적용되어 있어서 &lt;/span&gt;&lt;span&gt;전체 페이지 높이가 고정되고, RootLayout의 레이아웃 구조와 충돌하면서 &lt;/span&gt;&lt;span&gt;footer가 제대로 배치되지 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;493&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drIpVA/dJMcacIieKn/CUyc2lh96q60aKkFFNuIG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drIpVA/dJMcacIieKn/CUyc2lh96q60aKkFFNuIG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drIpVA/dJMcacIieKn/CUyc2lh96q60aKkFFNuIG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrIpVA%2FdJMcacIieKn%2FCUyc2lh96q60aKkFFNuIG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;605&quot; height=&quot;493&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;493&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;페이지 컴포넌트에서 불필요한 고정 높이(h-screen)와 제약(min-h-0)을 제거해서 &lt;/span&gt;&lt;span&gt;RootLayout의 전역 레이아웃 설정과 충돌하지 않도록 했다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;레이아웃 문제는 항상 &quot;전역(Root) 문제일 거야&quot;라고 생각하기 쉬운데, 실제로는 특정 페이지 컴포넌트의 wrapper 설정이 원인인 경우가 많다!는걸 다시 한번.. 배웠다.&lt;/span&gt;&lt;/p&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <category>TiTaS</category>
      <category>우테코</category>
      <category>토이프로젝트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/513</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EB%A7%9E%EC%B6%A4%ED%98%95-TTS-%EA%B2%B0%EA%B3%BC-%EB%AA%A8%EB%8B%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%B6%95-%EB%96%A0%EB%B2%84%EB%A6%AC%EB%8A%94-Footer#entry513comment</comments>
      <pubDate>Sat, 22 Nov 2025 19:47:47 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5 주차 | 완성도를 높이는 마지막 1%: 타입, 데이터, 그리고 정규식</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EC%99%84%EC%84%B1%EB%8F%84%EB%A5%BC-%EB%86%92%EC%9D%B4%EB%8A%94-%EB%A7%88%EC%A7%80%EB%A7%89-1-%ED%83%80%EC%9E%85-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%A0%95%EA%B7%9C%EC%8B%9D</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MVP 기능 구현을 마치고 배포까지 성공했지만, 실제로 앱을 돌려보면서 발견된 버그와 사용자 경험을 해치는 요소들을 수정하는 데 시간을 쏟았다. 특히 TypeScript의 타입 시스템과 데이터 초기화 시점, 그리고 텍스트 분석의 정교함을 높이는 과정에서 겪은 문제들을 정리해 본다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. TypeScript 타입 확장과 Type Guard: WeakSpot에 없는 속성을 써야 할 때&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Review 페이지에서 틀린 단어를 클릭하면 해당 단어가 포함된 전체 문장(lineContent)을 읽어주는 기능을 추가하려 했다. 그런데 기존에 정의해 둔 WeakSpot 타입에는 문장 정보를 담는 필드가 없었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;단순히 types.ts의 원본 인터페이스를 수정하면 간단하겠지만, WeakSpot은 DB(LocalStorage)에 저장되는 스키마 형태라 함부로 필드를 추가하면 기존 데이터와 충돌이 날 수 있었다. 나는 런타임에서만 잠시 필요한 데이터를 기존 타입에 덧붙여서 사용해야 했다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 과정에서 WeakSpot 배열을 filter로 걸러낼 때 TypeScript가 &quot;이 객체에 lineContent가 있다는 것을 보장할 수 없다&quot;며 에러를 뱉었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 TypeScript의&amp;nbsp;Type Predicate (사용자 정의 타입 가드)&amp;nbsp;문법을 사용했다. filter 함수 내부에서 e is WeakSpot &amp;amp; { lineContent: string }라고 반환 타입을 명시해 줌으로써, 필터링을 통과한 객체들은 반드시 lineContent 속성을 가지고 있음을 컴파일러에게 보장해 주었다. 덕분에 원본 타입 정의를 건드리지 않고도 안전하게 타입을 확장해 기능을 구현할 수 있었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 데이터 하이드레이션 이슈: 새로고침하면 데이터가 깜빡이는 문제&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;앱을 배포하고 나서 보니, 새로고침을 할 때마다 찰나의 순간 동안 데이터가 비어 있다가 채워지거나, 어떤 경우에는 아예 로드되지 않는 현상이 있었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원인은 Zustand 스토어의 초기화 시점과 LocalStorage 데이터를 불러오는 시점의 차이였다. Zustand는 기본적으로 메모리 상의 상태를 관리하는데, 앱이 처음 켜지는 시점(main.tsx 또는 RootLayout 마운트 시점)에 LocalStorage의 데이터를 스토어로 동기화해 주는 로직이 명확하지 않았다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 RootLayout 컴포넌트가 마운트되는 즉시 loadInitialData 액션을 강제로 호출하도록 useEffect를 배치했다. 이를 통해 앱이 시작되자마자 브라우저 저장소의 데이터를 메모리로 퍼올려(Hydration), 사용자가 빈 화면을 보는 일이 없도록 데이터 흐름을 고정했다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 데이터 정제: &quot;Hello&quot;와 &quot;Hello,&quot;는 다른 단어인가?&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;약점 분석(Review) 페이지를 만들고 테스트를 하는데 통계가 이상했다. Hello라는 단어를 틀렸는데, 통계에는 Hello, Hello,, Hello?가 모두 다른 단어로 집계되어 순위에 올라와 있었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컴퓨터 입장에서는 문장 부호 하나만 달라도 다른 문자열로 인식하기 때문이었다. 진정한 언어 학습 분석을 위해서는 순수한 '단어'만 추출해야 했다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JavaScript의 replace 메서드와 정규표현식(Regex)을 도입했다. 문장에서 단어를 추출하거나 비교하기 전에 /[.,?!]/g 패턴을 사용하여 모든 문장 부호를 빈 문자열로 치환하는 전처리 과정을 추가했다. 그 결과, 문장 부호가 붙어있든 아니든 순수 단어 빈도수를 정확하게 집계할 수 있게 되었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4. 레이아웃 디테일: 반응형에서의 배치 순서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;PC 화면에서는 캘린더가 왼쪽, 통계가 오른쪽에 있는 것이 자연스러웠다. 하지만 모바일 화면으로 줄였을 때, 통계가 먼저 나오고 캘린더가 그 아래로 내려가는 배치가 되었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용자 흐름상 모바일에서는 &quot;오늘 연습했나?&quot;를 보여주는 캘린더가 가장 먼저 보여야 동기 부여가 될 것 같았다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;CSS Flexbox의 order 속성을 사용하거나, HTML 구조 자체를 뒤집는 대신 Flex 컨테이너의 방향 설정을 조정하여 해결했다. 단순히 flex-col로 쌓이는 구조에서, 모바일 우선(Mobile First) 설계를 고려하여 중요한 정보인 캘린더가 시각적으로 상단에 오도록 레이아웃 배치 순서를 재조정했다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마치며&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;거창한 기능을 추가한 것은 아니었지만, 오늘 수정한 것들은 서비스의 품질을 결정짓는 중요한 디테일이었다. 타입 안정성을 확보하고, 데이터 흐름을 매끄럽게 하고, 분석 로직을 정교하게 다듬는 과정. 어쩌면 개발의 진짜 재미는 거대한 아키텍처를 짤 때보다 이런 디테일한 문제들을 하나씩 해결하며 완성도를 높여가는 과정에 있는지도 모르겠다.&lt;/p&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <category>TiTaS</category>
      <category>오픈미션</category>
      <category>우테코</category>
      <category>프리코스</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/512</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EC%99%84%EC%84%B1%EB%8F%84%EB%A5%BC-%EB%86%92%EC%9D%B4%EB%8A%94-%EB%A7%88%EC%A7%80%EB%A7%89-1-%ED%83%80%EC%9E%85-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%A0%95%EA%B7%9C%EC%8B%9D#entry512comment</comments>
      <pubDate>Sat, 22 Nov 2025 19:17:38 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5 주차 | 기능은 완성했는데... (UX, 삭제해도 안사라지는 데이터, CSS)</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EA%B8%B0%EB%8A%A5%EC%9D%80-%EC%99%84%EC%84%B1%ED%96%88%EB%8A%94%EB%8D%B0-UX-%EC%82%AD%EC%A0%9C%ED%95%B4%EB%8F%84-%EC%95%88%EC%82%AC%EB%9D%BC%EC%A7%80%EB%8A%94-%EB%8D%B0%EC%9D%B4%ED%84%B0-CSS</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;핵심 엔진인 STT, TTS, Diff 구현과 그 외 기능을 구현 후 프로젝트가 다 끝난 줄 알았다. 하지만 그것은 착각이었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;막상 직접 사용해보니 브라우저 기본 경고창은 투박했고, 삭제한 데이터는 새로고침하면 다시 살아났다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;페이지마다 여백은 제각각이라 시각적으로 불안정했다. 기능적으로는 작동하지만 사용하기에는 불편한, 미완성의 상태였다. 부족한 디테일을 잡기 위해 코드와 씨름했던 시간이었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 토스트 라이브러리 도입과 Stale Closure 문제&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 사용자 피드백을 브라우저 기본 기능인 alert으로 처리했다. 하지만 삭제, 저장, 역할 전환 등 인터랙션이 많아질수록 매번 팝업을 띄우는 방식은 사용자 경험을 해쳤다. 그래서 react-hot-toast 라이브러리를 도입해 더 부드러운 피드백을 주기로 했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;그런데 여기서 예상치 못한 기술적 난관을 만났다. 토스트 메시지 안에 삭제하시겠습니까 라는 문구와 함께 확인 버튼을 넣고, 확인을 누르면 삭제 함수가 실행되도록 구현했다. 그러나 버튼을 눌러도 상태가 변하지 않거나, 엉뚱한 데이터가 삭제되려 하는 등 비정상적으로 동작했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763746596187&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 실패한 코드 (Hook 방식)
const deleteScript = useAppStore((s) =&amp;gt; s.deleteScript);

toast((t) =&amp;gt; (
  &amp;lt;button onClick={() =&amp;gt; deleteScript(id)}&amp;gt;Confirm&amp;lt;/button&amp;gt; 
  // 이 시점의 deleteScript는 과거의 상태를 기억하고 있거나, 
  // 토스트 내부 컨텍스트에서 제대로 바인딩되지 않았다.
));&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;원인은 리액트의 클로저 특성 때문이었다. 훅을 통해 가져온 함수는 컴포넌트가 렌더링될 당시의 스코프를 기억한다. 하지만 토스트는 리액트 컴포넌트 트리 외부 혹은 별도의 컨텍스트에서 렌더링되거나 비동기로 작동하면서, 이미 지나가버린 과거의 상태를 참조하고 있었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;문제를 해결하기 위해 Zustand가 제공하는 getState 메서드를 활용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763746620201&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 성공한 코드 
import { useAppStore } from '@/store/appStore';

// 훅이 아니라 스토어 자체에서 함수를 꺼내 쓴다.
useAppStore.getState().deleteScript(id);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;리액트 훅을 거치지 않고 스토어 인스턴스에 직접 접근하여 함수를 호출함으로써 항상 최신 상태를 참조하도록 수정했다. 이 경험을 통해 리액트의 라이프사이클 밖에서 상태를 다룰 때의 위험성과, 상태 관리 라이브러리의 내부 동작 원리를 다시 한번 이해하게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;삭제했는데 왜 다시 살아날까, LocalStorage 동기화&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;대본 삭제 기능을 구현하고 테스트를 하는데 기이한 현상을 목격했다. 삭제 버튼을 누르면 화면 목록에서는 분명 사라진다. 그런데 새로고침을 하면 지웠던 대본이 다시 목록에 나타나는 것이었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;원인은 UI 상태와 영구 저장소 간의 불일치였다. 나는 Zustand의 메모리 상의 상태만 업데이트하고, 정작 영구 저장소인 localStorage를 업데이트하는 코드를 누락했거나 시점을 잘못 잡고 있었다. 화면은 리액트 상태를 보고 렌더링 되니 사라진 것처럼 보였지만, 원본 데이터는 브라우저 저장소에 그대로 살아있었던 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 삭제 액션이 실행될 때 두 가지 작업이 반드시 동시에 일어나도록 로직을 수정했다. Zustand 스토어 배열에서 해당 ID를 제거하여 UI에 즉시 반영함과 동시에, 변경된 배열을 localStorage에 덮어쓰기 하여 데이터 영속성을 보장했다. 이 두 과정이 하나의 트랜잭션처럼 묶여야 비로소 완전한 삭제가 이루어진다는, 어찌 보면 당연하지만 놓치기 쉬운 기본기를 다시 배웠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이아웃의 배신, 조건부 패딩 적용&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;레이아웃의 통일성을 위해 최상위 컴포넌트에서 전역적으로 패딩을 주었더니, 대시보드 페이지는 보기 좋게 나왔다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;하지만 대화 연습 페이지에 들어가니 문제가 발생했다. 채팅 인터페이스는 화면을 꽉 채워야 몰입감이 생기는데, 전역 패딩 때문에 채팅창이 공중에 붕 뜨고 하단 입력창은 모서리가 잘려 나가는 현상이 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763746730880&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const isTalkPage = location.pathname.startsWith('/talk');

// 연습 페이지면 패딩 0, 아니면 패딩 2
&amp;lt;main className={`flex-1 ${isTalkPage ? '' : 'p-2'}`}&amp;gt;
  &amp;lt;Outlet /&amp;gt;
&amp;lt;/main&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;모든 페이지에 똑같은 여백을 준다는 안일한 설계를 수정해야 했다. 현재 경로를 감지하여 연습 페이지일 경우 패딩을 제거하고, 그 외의 페이지에만 여백을 주는 조건부 렌더링 방식을 적용했다. 또한 하위 컴포넌트들이 예상치 못하게 스타일을 상속받는 문제를 막기 위해, 디자인 시스템의 변수로 계층을 명확히 분리하여 스타일을 안정화했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;돌아가는 코드와 쓸만한 코드의 차이를 메우는 과정이었다. 단순히 경고창을 띄우는 것과 토스트 메시지를 띄우는 것은 기술적 난이도가 다르다. 하지만 사용자가 느끼는 서비스의 질은 그런 사소한 디테일에서 결정된다. 패딩값 몇 픽셀을 조절하고, 데이터의 동기화를 맞추는 과정은 지루할 수 있지만, 이런 디테일을 챙기는 것이 개발자의 진짜 역량임을 느꼈다.&lt;/p&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <category>TiTaS</category>
      <category>uiux</category>
      <category>오픈미션</category>
      <category>우테코</category>
      <category>프리코스</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/511</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%EA%B8%B0%EB%8A%A5%EC%9D%80-%EC%99%84%EC%84%B1%ED%96%88%EB%8A%94%EB%8D%B0-UX-%EC%82%AD%EC%A0%9C%ED%95%B4%EB%8F%84-%EC%95%88%EC%82%AC%EB%9D%BC%EC%A7%80%EB%8A%94-%EB%8D%B0%EC%9D%B4%ED%84%B0-CSS#entry511comment</comments>
      <pubDate>Sat, 22 Nov 2025 02:53:35 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5 주차 | Tailwind v4 vs v3: 죽음의 핑퐁 게임, 승자는 결국 v4였다</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-Tailwind-v4-vs-v3-%EC%A3%BD%EC%9D%8C%EC%9D%98-%ED%95%91%ED%90%81-%EA%B2%8C%EC%9E%84-%EC%8A%B9%EC%9E%90%EB%8A%94-%EA%B2%B0%EA%B5%AD-v4%EC%98%80%EB%8B%A4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 초기, 나를 괴롭혔던건 다름아닌 CSS 프레임워크 설정이었다. 2025년 현재 최신 버전인 Tailwind CSS v4를 호기롭게 도전했지만, 설정과정은 순탄하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 당연히 v4를 선택했다. tailwind.confimg.js파일이 사라지고 CSS 파일 하나로 설정이 가능하다는 점이 굉장히 매력적이었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;첫번째 벽: @theme 문법 에러&lt;/h2&gt;
&lt;pre id=&quot;code_1763745181831&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@theme {
  --font-family-sans: 'Inter', system-ui, sans-serif;
  --color-primary: #8b7355;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 서버를 돌렸더니 바로 터졌다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1763745202834&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[postcss] Unknown word --font-family-sans&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;알고 보니 @theme 블록은 Tailwind v4 표준 문법이 아니었다. &lt;/span&gt;&lt;span&gt;PostCSS가 이걸 전혀 인식 못 하고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해결:&amp;nbsp;:root로 바꿨다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1763745255832&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;:root {
  --font-family-sans: 'Inter', system-ui, sans-serif;
  --color-primary: #8b7355;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;표준 CSS 변수 선언 방식으로 바꾸니까 바로 됐다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;첫 삽질 종료.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;두 번째 벽: PostCSS 설정 파일 충돌&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CSS 변수는 고쳤는데 이번엔 다른 에러가 떴다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1763745319179&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Failed to load PostCSS config&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;postcss.config.js 파일을 열어봤더니... &lt;/span&gt;&lt;span&gt;CommonJS랑 ESM이 꼬여 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해결:&amp;nbsp;.cjs&amp;nbsp;확장자로 바꿨다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;확장자를&amp;nbsp;.cjs로 바꾸고&amp;nbsp;module.exports&amp;nbsp;형식으로 통일했더니 해결됐다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;세 번째 벽:&amp;nbsp;@import&amp;nbsp;vs&amp;nbsp;@tailwind&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1763745389385&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@import 'tailwindcss';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CSS 파일 상단에 이렇게 써뒀었다. 이게 Vite 환경에서 제대로 작동을 안 했다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;스타일이 간헐적으로 안 먹히는 현상이 발생했다.&lt;/span&gt; &lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1763745420310&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 바꾸니까 완벽하게 작동했다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;네 번째 벽: 갑자기 모든 CSS가 다 깨졌다&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기까지 오면서 이것저것 만지다 보니... &lt;/span&gt;&lt;span&gt;화면이 완전히 망가졌다. &lt;/span&gt;&lt;span&gt;스타일이 하나도 안 먹히고, 레이아웃도 다 깨졌다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원인을 찾았다&lt;/span&gt;&lt;br /&gt;&lt;span&gt;1. :root 변수 선언 순서가 잘못됐다&lt;/span&gt;&lt;br /&gt;&lt;span&gt;2. @tailwind 지시어 위치가 엉뚱했다&lt;/span&gt;&lt;br /&gt;&lt;span&gt;3. CSS 변수 이름이 중구난방이었다&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(--text-primary&amp;nbsp;vs&amp;nbsp;--color-text-primary&amp;nbsp;등)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span&gt;해결: CSS 파일 구조를 완전히 정리했다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;다섯 번째 벽: 이번엔 공식문서다&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. @import 'tailwindcss' 사용&lt;/span&gt;&lt;br /&gt;&lt;span&gt;2. @theme { } 블록으로 변수 정의&lt;/span&gt;&lt;br /&gt;&lt;span&gt;3. Vite 플러그인 설정&lt;/span&gt;&lt;br /&gt;&lt;span&gt;4. v3 문법 완전히 제거&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tailwindCSS의 삽질로 부터 벗어날 수 있었다. 앞으로 공식문서랑 친해져야겠다. 공식문서 짱&lt;/p&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <category>tailwindv4</category>
      <category>TiTaS</category>
      <category>오픈미션</category>
      <category>우테코</category>
      <category>토이프로젝트</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/510</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-Tailwind-v4-vs-v3-%EC%A3%BD%EC%9D%8C%EC%9D%98-%ED%95%91%ED%90%81-%EA%B2%8C%EC%9E%84-%EC%8A%B9%EC%9E%90%EB%8A%94-%EA%B2%B0%EA%B5%AD-v4%EC%98%80%EB%8B%A4#entry510comment</comments>
      <pubDate>Sat, 22 Nov 2025 02:28:16 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5 주차 | 티키타카 흐름 설계 (STT, Diff, TSS 엔진 연결)</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%ED%8B%B0%ED%82%A4%ED%83%80%EC%B9%B4-%ED%9D%90%EB%A6%84-%EC%84%A4%EA%B3%84-STT-Diff-TSS-%EC%97%94%EC%A7%84-%EC%97%B0%EA%B2%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 과정에서는 TiTas의 첫 번째 엔진 데이터를 가공해 스마트 파서를 하는 것까지 했었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 핵심기능 TTS, Diff, TSS를 달아서 티카티카가 되게 구현하는 것이 목표이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TTS란? 글자를 소리로 읽어주는 기술&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diff란? 두 데이터/문서/코드 차이점을 찾아 비교해주는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SST란? 음성을 문자로 바꾸는 기술&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 구조적 난관: 파일은 만들었지만, '뇌'가 없었다. (Zustand 도입)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;TalkPage.tsx, CreatorPage.tsx 등 핵심 페이지 파일들을 생성하고 UI를 그리기 시작했다. 하지만 곧바로 막막함이 밀려왔다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&quot;사용자가 Creator 페이지에서 만든 스크립트를 Talk 페이지로 어떻게 넘기지?&quot;&lt;/i&gt; &lt;i&gt;&quot;연습이 끝나면 점수와 로그를 어디에 저장했다가 대시보드에서 보여주지?&quot;&lt;/i&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;단순히 useState와 props 전달만으로는 감당할 수 없었다. 컴포넌트 뎁스(Depth)가 깊어질수록 코드는 지저분해질 게 뻔했고, 데이터 흐름이 꼬일 것이 눈에 보였다. '상태 관리'라는 뇌(Brain)가 없었던 것이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;작업을 잠시 멈추고 상태 관리 라이브러리를 도입하기로 결정했다. Redux는 너무 무거웠고, Context API는 렌더링 이슈가 걱정되었다. 그래서 가장 가볍고 Hook 친화적인 &lt;b&gt;Zustand&lt;/b&gt;를 선택했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;src/store/appStore.ts를 생성하고, 앱 전체에서 쓰일 핵심 데이터들을 '&lt;b&gt;단일 진실 공급원(Single Source of Truth)&lt;/b&gt;'으로 통합했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763743078919&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export interface AppState {
  allScripts: ScriptData[];   // 사용자가 만든 스크립트 목록
  practiceLogs: PracticeLog[]; // 연습 기록 및 약점 데이터
  // ...
  saveNewScript: (script: ScriptData) =&amp;gt; void; // 액션
  addNewPracticeLog: (logEntry: PracticeLog) =&amp;gt; void;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 결정 덕분에 각 페이지는 복잡한 로직 없이 Store에서 데이터를 꺼내 쓰고(Selector), 액션을 호출하기만 하면 되는 깔끔한 구조(MVC 패턴과 유사)를 갖추게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;checkWordDiff의 역할을 통해서 jsdiff의 데이터들을 입력받아 DiffResult[]로 가공하여 반환하는 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 기술적 난관:&amp;nbsp; 안녕하세요. 제 이름은 TS7016입니다.&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 순탄한 과정만 있었던 것은 아니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1차 위기: 타입이 있는데 왜 없다고 하니?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;diffChecker.ts파일을 생성하고 jsdiff를 import하는 순간 TypeScirpt가 TS7016: 모듈 'jsdiff'에 대한 선언 파일을 찾을 수 없습니다.라는 오류를 발생했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니까 @types가 누락이 되었을때 발생이 된다고 하길래 npm install -D @types/jsdiff를 시도했지만 역시나 E404:Not Found였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고보니 jsdiff라이브러리 자체에 이미 타입 파일이 포함되어 있다는 뜻이었다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 왜 TypeScript에서 이미 존재하는데 타입 파일을 찾지 못한다고 했을까? 미궁속으로 빠지던 찰나 AI한테 물어봤다. 라이브러리가 아니라 나의 tsconfig.json설정이었다. 최신 Vite 환경은 node_modules안의 타입을 읽어오는 방식에 대한 명확한 설정이 필요했기때문이다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 tsconfig.json의 compilerOptioins에 &quot;moduleResolution&quot;: &quot;bundler&quot; 옵션을 추가해 Vite 번들러의 모듈 해석을 따르라고 설정했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 설정하나로 오류도 사라졌으며 part 매개변수에서 any 타입 오류 역시 해결되었다. 즉! 1석 2조~ 효과가 나타난 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DoneCongratsGIF.gif&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rxkQd/dJMcaap76ut/jAVyQjRYFX4oowxEnbhiyk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rxkQd/dJMcaap76ut/jAVyQjRYFX4oowxEnbhiyk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rxkQd/dJMcaap76ut/jAVyQjRYFX4oowxEnbhiyk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/rxkQd/dJMcaap76ut/jAVyQjRYFX4oowxEnbhiyk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;182&quot; height=&quot;189&quot; data-filename=&quot;DoneCongratsGIF.gif&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2차 위기: diffWords is not a function (런타임 에러)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;타입 에러를 잡고 신나게 실행을 시켰는데, 이번엔 브라우저 화면이 하얗게 변했다. 콘솔을 보니 TypeError: diffWords is not a function 오류가 발생하고 있었다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;이건 CJS(CommonJS)와 ESM(ECMAScript Module)의 호환성 문제였다. jsdiff는 구식 CJS 방식으로 모듈을 내보내는데, 최신 Vite 환경에서는 이를 제대로 해석하지 못해 함수가 아닌 객체 껍데기만 가져오고 있었던 것이다. import * as JSDiff, require 등 온갖 방법을 시도해 봤지만, 모듈 구조가 너무 깊게 꼬여 있었다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size23&quot;&gt;해결: 과감한 라이브러리 교체 (diff)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류를 분석하는 데 시간을 더 쓰는 건 비효율적이라 판단했다. 나는 즉시 jsdiff를 삭제하고, API 사용법이 100% 동일하면서 모듈 호환성이 훨씬 뛰어난 &lt;b&gt;diff&lt;/b&gt; 라이브러리로 교체했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763743209797&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm uninstall jsdiff
npm install diff
npm install -D @types/diff&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1763743225853&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import * as Diff from 'diff'; 

export function checkWordDiff(...) {
  // 코드는 단 한 줄도 바꾸지 않아도 되었다!
  const diff = Diff.diffWords(original, spoken, { ignoreCase: true });
  // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 성공이었다. Diff 엔진은 완벽하게 작동했고, 사용자의 틀린 단어(Red)와 빼먹은 단어(Green)를 정확하게 시각화할 수 있었다. 때로는 문제를 붙들고 있기보다, 도구를 바꾸는 것이 정답일 때가 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 귀(STT)와 입(TSS) 훅 설계&lt;/h2&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;React는 상태가 변하면 UI를 다시 그리는 선언적 방식이다. 반면, 브라우저에 내장된 Web Speech API(STT/TTS)는 이벤트 기반의 명령형방식으로 작동한다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;이 둘을 그대로 섞어 쓰면 컴포넌트 안에 지저분한 이벤트 리스너 코드가 가득 차게 된다. 그래서 나는 이 둘을 매끄럽게 연결해 줄 커스텀 훅(Custom Hook)이라는 다리를 놓기로 했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;귀 만들기: useSpeechRecognition&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Web Speech API는 onstart, onend, onresult 같은 이벤트로 동작한다. 나는 useEffect를 사용해 컴포넌트가 마운트될 때 인스턴스를 생성하고, 이벤트가 발생할 때마다 useState의 세터 함수를 호출하도록 설계했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763743466155&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function useSpeechRecognition() {
  const [transcript, setTranscript] = useState('');
  const [isListening, setIsListening] = useState(false);

  useEffect(() =&amp;gt; {
    // ... 인스턴스 생성 ...
    
    // 바닐라 JS 이벤트를 React 상태로 변환
    recognition.onresult = (event) =&amp;gt; {
      const text = event.results[0][0].transcript;
      setTranscript(text); // 상태 업데이트 -&amp;gt; UI 렌더링
      setIsListening(false);
    };
  }, []);

  return { transcript, isListening, startListening, stopListening };
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;TypeScript의 태클: SpeechRecognitionEvent?&lt;/h4&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;여기서도 타입스크립트가 발목을 잡았다. event 객체의 타입을 지정하려는데 SpeechRecognitionEvent라는 타입을 찾지 못하거나, 브라우저마다(webkit...) 타입 정의가 달랐다. 결국 실용적인 해결을 위해 이벤트 객체는 any로 처리하고, 대신 window 객체에 대한 타입 확장을 통해 SpeechRecognition 생성자 자체를 인식시키는 데 집중했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;  입 만들기: useTTS&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TTS(Text-to-Speech)는 비교적 간단했지만, &quot;말이 끝난 시점&quot;을 아는 것이 중요했다. 그래야 컴퓨터가 말을 다 마친 후에 사용자에게 턴을 넘길 수 있기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1763743509731&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const speak = (text: string, onEnd?: () =&amp;gt; void) =&amp;gt; {
  const utterance = new SpeechSynthesisUtterance(text);
  
  utterance.onend = () =&amp;gt; {
    setIsSpeaking(false);
    if (onEnd) onEnd(); // 말이 끝나면 다음 동작 실행 (턴 넘김)
  };

  window.speechSynthesis.speak(utterance);
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과: 깔끔해진 UI 컴포넌트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 훅 덕분에 복잡한 비동기 로직이 담긴 TalkPage.tsx는 놀라울 정도로 단순해졌다. UI 컴포넌트는 이제 복잡한 API 명세를 알 필요 없이, &quot;듣고 있니?&quot;, &quot;말해!&quot; 같은 직관적인 명령만 내리면 되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1763743547103&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { transcript, isListening } = useSpeechRecognition();
const { speak } = useTTS();

// 사용법이 이렇게나 심플해졌다!
useEffect(() =&amp;gt; {
  if (transcript) handleUserInput(transcript);
}, [transcript]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 기술적 도전: 편한 길을 두고, 굳이 '맨땅에 헤딩'을 한 이유&lt;/h2&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;단순 기능 구현보다는 학습에 중점을 두어, 외부 라이브러리 대신 Web API를 직접 활용해 기능을 구현했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;react-speech-recognition 등을 사용하면 STT와 TTS를 쉽게 구현할 수 있지만, 프로젝트의 핵심인 음성 인터랙션 기능을 외부 의존성 없이 직접 제어하고자 했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3,0&quot; data-ke-size=&quot;size16&quot;&gt;브라우저의 '날것(Raw)'인 window.speechSynthesis를 직접 제어하는 영역이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3,0&quot; data-ke-size=&quot;size16&quot;&gt;단순히 API를 호출하는 수준을 넘어, 예측하기 힘든 비동기 이벤트 흐름을 리액트의 라이프사이클과 오차 없이 동기화하는 과정은 예상보다 훨씬 깊은 원리 이해를 요구했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;3,1&quot; data-ke-size=&quot;size16&quot;&gt;SpeechRecognitionEvent의 타입 정의와 브라우저 호환성 문제를 하나씩 해결해 나갔지만, 해결할수록 자바스크립트 생태계가 가진 깊이에 오히려 압도되는 기분이었다. 리액트나 타입스크립트라는 강력한 도구도 결국 순수 자바스크립트와 Web API라는 거대한 토대 위에 서 있다는 사실을, 그리고 나는 이제 겨우 그 토대의 표면을 긁어보았을 뿐이라는 사실을 뼈저리게 실감했다. 앞으로 채워야 할 빈틈이 여전히 많음을 확인하는 계기가 되었다. (다들 어떻게 개발자를 하는걸까..? 개발이란걸 하면할수록 공부할게 너무 많다. 현직 개발자분들은 정말 대단하다.)&lt;/p&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <category>STT</category>
      <category>TiTaS</category>
      <category>TSS</category>
      <category>영어회화</category>
      <category>오픈미션</category>
      <category>우테코</category>
      <category>토이프로젝트</category>
      <category>프리코스</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/509</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-45-%EC%A3%BC%EC%B0%A8-%ED%8B%B0%ED%82%A4%ED%83%80%EC%B9%B4-%ED%9D%90%EB%A6%84-%EC%84%A4%EA%B3%84-STT-Diff-TSS-%EC%97%94%EC%A7%84-%EC%97%B0%EA%B2%B0#entry509comment</comments>
      <pubDate>Mon, 17 Nov 2025 01:15:36 +0900</pubDate>
    </item>
    <item>
      <title>[우테코] 프리코스 4,5주차 | TiTas 기획 및 핵심 엔진: 스마트 파서 설계</title>
      <link>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-AI%EA%B0%80-%EC%95%84%EB%8B%8C-%EC%8B%A4%EC%A0%84-%ED%9B%88%EB%A0%A8%EC%9E%A5%EC%9D%B4-%ED%95%84%EC%9A%94%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4-TiTaS-1</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 TiTas인가?! AI로 할 수 없는 빈틈을 노려보자!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 우테코 마지막 미션 주차이다. 시간이 빠르게 지나갔다. 이번 과정은 자바스크립트에 대해 스스로 부족한 점이 많다는 것을 다시금 느끼는 시간이었다. 마지막 미션은 오픈 미션이라, 말 그대로 모든 것이 나에게 달려있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 혼자서 직접 프로젝트를 만들어보고 싶어 따로 협업을 하지 않았다. 혼자 하려면 고난도 미션이나 안 써본 언어를 선택해야 할 수도 있었다. 하지만 나는 리액트나 타입스크립트 역시 완벽하지 않고 여전히 부족하다고 느낀다. 그래서 기본 언어는 자바스크립트를 사용하되, 리액트와 타입스크립트를 활용해 보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 아이디어가 떠올랐지만 마땅히 제출할 만한 것은 없었다. 그렇게 아이디어 구상에만 4~5일을 썼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 개인적으로 영어 회화 공부를 시작했는데, 이와 관련된 아이디어를 구상하게 되었다. 아마 이 프로젝트를 보고 &quot;요즘엔 AI가 있는데 굳이?&quot;라는 생각을 할 수도 있다. 나 역시 그 점에 대해 많이 고민했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 AI 번역기나 챗봇은 '완벽한 정답'을 즉시 알려준다. 나는 언어 학습이 정답을 얻는 과정이 아니라, 스스로 발전하며 '근육을 만드는 과정'이라 생각하기에 이 프로젝트를 선택했다. AI는 수동적인 학습에서는 최고지만, 능동적인 훈련에는 한계가 있다고 생각한다. 정답을 알려주는 AI보다 스스로 내 대화문(대본)을 소리내어 반복 연습하고 직접 부딪혀볼 수 있는 실전 연습장이 필요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 TiTaS라는 프로젝트를 구상했다. TiTaS는 'Tiki-Taka Script'의 약자이다. (프로젝트 이름을 정하는 데도 반나절이 걸렸다. 딱 입에 달라붙는 이름이 없었기 때문이다!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간략하게 프로젝트를 소개하자면, 이 프로젝트는 기존 AI가 해결하지 못하는 다음 세 가지 문제점에서 출발했다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;AI는 '정해진 대본'을 주고받는 티키타카 경험을 제공하지 못한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AI와의 대화는 '자유 대화(Free-talking)'에 가까워, &quot;카페에서 주문하기&quot;처럼 특정 상황을 반복 연습하고 싶어도 대화가 쉽게 벗어난다. TiTaS는 명확한 '롤플레잉' 대본을 제공하여, 사용자가 원하는 상황을 집중적으로 훈련할 수 있게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AI는 사소한 발음이나 실수를 실시간으로 채점하지 못하며, 정답 및 틀린 단어 형태로 명확하게 피드백을 주지 못한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AI는 문맥으로 사용자의 실수를 이해하고 넘어가거나 &quot;Good job!&quot; 정도로만 반응한다. 하지만 TiTaS는 사용자가 &quot;I want &lt;b&gt;a&lt;/b&gt; apple&quot;이라고 했는지 &quot;&lt;b&gt;an&lt;/b&gt; apple&quot;이라고 했는지, 'R'과 'L' 발음을 혼동하지는 않았는지 즉각적으로 분석하여 명확한 정답/오답 피드백을 주는 것을 목표로 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AI는 나의 실수 데이터를 누적 분석하여, '가장 많이 틀린 약점 Top 4' 같은 개인화된 대시보드를 만들지 못한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AI와의 대화는 휘발성이다. 어제 틀렸던 '전치사' 실수를 오늘 또 반복해도, AI는 &quot;당신은 3일째 'at'과 'in'을 혼용하고 있습니다&quot;라고 알려주지 않는다. TiTaS는 이 모든 실수 데이터를 누적하여 사용자의 진짜 '약점 지도'를 그려준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 이 세 가지 문제점을 해결하기 위해, React와 TypeScript 환경에서 파서와 데이터 분석 엔진을 이용해 이번 오픈 미션에 도전해보려고 한다. 여기서 '파서'란, 사용자의 음성 텍스트와 정답 스크립트를 실시간으로 비교하여 '어떤 단어를 빠뜨렸는지', '어떤 단어를 잘못 말했는지'를 분석하는 핵심 로직이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;독창성을 설계하기 위해 나는 어떻게 하면 좋을까? A/B파서가 아닌 스마트 파서!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 아이디어는 사용자가 A,B 전체를 스크립트에 입력하는 방법이 떠올랐다. 하지만 이 방법은 장기적으로 유지보수 측면을 고려했을때 좋은방법이 아닌거 같았다. 그래서 Speaker로 바꾼뒤 Speaker에 따라서 색상을 주는 방식으로 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 컬러 기반 화자를 지정해 사용자가 직관적으로 컬러를 선택함으로 화자를 구분할 수 있는 것이다! 스마트 파서는 사용자가 교과서의 긴 단락을 복붙해도 엔진에서는 그것을 문장 단위(.?!)로 자동 분리해 티카타카의 흐름을 생성할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 바로 AI가 없는 고전적인 방법! 나한테는 독창성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;엔진을 바닐라 자바스크립트를 통해 만들어보아요!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트, 타입스크립트를 사용하지만 프로젝트의 중심인 파서 엔진만큼은 자바스크립트를 사용한다. 의도적으로 리액트를 의존하지 않기 위해 자바스크립트 함수로 설계를 했다. 이것이 관심사 분의의 원칙이며 알고리즘 논리를 증명하는 방식이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;parser.ts의 논리는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1763307337321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ... (for 루프 내부) ...
const rawLineBlock = parts[i + 1] ? parts[i + 1].trim() : ''; // '긴 단락'
const speakerId = speakerIdPrefix.replace(':', '');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 사용자가 입력한 긴 단락(rawLinkBlock)을 받는다.&lt;/p&gt;
&lt;pre id=&quot;code_1763307375683&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 문장 종결 부호(' .?! ') 자체를 포함하여 분리하는 정규식
const SENTENCE_SPLIT_REGEX = /(.*?[.?!])\s*/g;

// ... (if 블록 내부) ...
if (rawLineBlock.length &amp;gt; 0 &amp;amp;&amp;amp; speakerId) {
  
  // 정규식으로 문장 배열 분리
  const sentences = rawLineBlock.match(SENTENCE_SPLIT_REGEX);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 미리 정의한 정규식(SENTENCE_SPLIT_REGEX)을 사용해 이 단락을 문장 단위로 분리(split)한다.&lt;/p&gt;
&lt;pre id=&quot;code_1763307426269&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (sentences &amp;amp;&amp;amp; sentences.length &amp;gt; 0) {
    // '분리된 문장을 각각 순회하며 데이터 생성
    for (const sentence of sentences) {
      const trimmedLine = sentence.trim();
      if (trimmedLine.length &amp;gt; 0) {
        resultLines.push({
          id: crypto.randomUUID(),
          speakerId: speakerId,
          speakerColor: speakerMap[speakerId] || '#AAAAAA',
          originalLine: trimmedLine, // 긴단락이 아닌 개별 문장
          isUserTurn: speakerId === 'Speaker 1',
        });
      }
    }
  } else {
    // 정규식에 매칭되지 않는 문장 처리
    resultLines.push({
      id: crypto.randomUUID(),
      speakerId: speakerId,
      speakerColor: speakerMap[speakerId] || '#AAAAAA',
      originalLine: rawLineBlock,
      isUserTurn: speakerId === 'Speaker 1',
    });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 분리된 문장을 각각 DialogueLine 타입에 맞춰 id, speakerId, speaerColor등의 정보와 함께 가공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 최종 결과인 자료구조(DialogueLine[]) 배열에 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 통해서 리액트와 독립되게 하고 테스트에도 용이하게 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;엔진 연결: CreatorPage.tsx UI연동&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진 완성 후, CreaterPage.tsx를 일단 UI 껍데기로만 만들어서 React와 Tailwind로 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 Add버튼을 클릭하면 handleAddLine함수가 실행되는 구조이다. 이 함수가 실행될때 parseScript()엔진을 호출해, 엔진이 반환한 자료구조(newLines)를 React state(setScriptLines)에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 연결로 긴 단락을 붙여 넣어도 UI에 문장 단위로 깔끔하게 쌓이는 걸 확인할 수 있담!&lt;/p&gt;</description>
      <category> ️ 우테코-프리코스/프리코스 4~5주차</category>
      <category>1인개발</category>
      <category>react</category>
      <category>TiTaS</category>
      <category>typescript</category>
      <category>영어회화</category>
      <category>오픈미션</category>
      <category>우테코</category>
      <category>토이프로젝트</category>
      <category>프로젝트기획</category>
      <category>프리코스</category>
      <author>코딩하세현</author>
      <guid isPermaLink="true">https://recordoftheday.tistory.com/508</guid>
      <comments>https://recordoftheday.tistory.com/entry/%EC%9A%B0%ED%85%8C%EC%BD%94-AI%EA%B0%80-%EC%95%84%EB%8B%8C-%EC%8B%A4%EC%A0%84-%ED%9B%88%EB%A0%A8%EC%9E%A5%EC%9D%B4-%ED%95%84%EC%9A%94%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4-TiTaS-1#entry508comment</comments>
      <pubDate>Thu, 13 Nov 2025 13:22:49 +0900</pubDate>
    </item>
  </channel>
</rss>