[TS] 다시 정리하는 TypeScript - 1

Ganziman·2025년 7월 10일
6
post-thumbnail

안녕하세요! 😊
타입스크립트를 공부하면서 헷갈렸던 부분들을 직접 정리해보았습니다.
개인적인 학습 기록이지만, 누군가에게 도움이 되셨으면 좋겠습니다! 🙇🏻‍♂️

왜 다시 공부하려고 했을까?

현재 실무에서 TypeScript를 사용한 지 어느덧 2년을 바라보고 있습니다. 다양한 프로젝트를 경험하면서 동료 개발자들과의 협업도 많아졌고, 자연스럽게 '타입을 더 명확하고 유연하게 설계하는 방법은 없을까?'라는 고민이 생기기 시작했습니다.

간단하게 예를 들어, 아래와 같은 구조를 만들었던 적이 있습니다.

type Person = {
  name: string;
  age: number;
  gender: "MALE" | "FEMALE";
  address: string;
  job: "developer" | "student" | "designer";
};

type PersonSummary = {
  name: string;
  age: number;
  address: string;
};

당시에는 구조가 조금만 달라도 별도로 타입을 만들곤 했는데, 나중에 Omit 유틸리티 타입을 활용하면 더 간결하게 표현할 수 있다는 것을 알게 되었습니다.

type PersonSummary = Omit<Person, "gender" | "job">;

이처럼 타입스크립트에는 실무에서 더 유연하게 활용할 수 있는 기능들이 많다는 걸 새삼 느끼게 되었고, 이를 체계적으로 공부해보고 싶다는 생각이 들었습니다.

마침 한 입 챌린지 6기가 열리게 되어, 타입스크립트를 주제로 참여하게 되었습니다!
혼자 공부하면 느려질 때도 있고 지루해질 수 있는데, 이번 기회를 통해 집중력 있게 학습하고자 합니다.

이번 포스팅은 Day 1부터 Day 7까지, 챌린지 수업과 퀴즈를 따라가며 배운 내용과 인사이트를 정리해보려고 합니다!

Day 1️⃣ - 타입스크립트?

자바스크립트를 더 안전하게 사용할 수 있도록 타입 관련 기능을 추가한 언어입니다.
자바스크립트의 유연함을 유지하면서, 타입 시스템을 도입해 더 안정적인 개발이 가능하도록 설계되었습니다.

모든 프로그래밍 언어는 "타입 시스템"을 갖고 있습니다.
타입 시스템의 차이에 따라 언어의 특징이 달라지게 됩니다.

각 언어는 타입 시스템을 가지고 있어 정적 타입 시스템이나 동적 타입 시스템을 갖게 되는데요!

대표적으로 정적 타입 시스템동적 타입 시스템이 있습니다.

⚡️ 정적 타입 시스템

  • 코드 실행 이전에 모든 변수의 타입을 고정적으로 결정합니다.
  • 엄격하고 고정적인 시스템
  • 컴파일 단계에서 타입 오류를 미리 발견 가능합니다.
    ex) Java, C, C++, Go 등...

🧱 동적 타입 시스템

  • 코드를 실행하는 시점에 변수의 타입을 유동적으로 결정합니다.
  • 자유롭고 유연한 시스템
    ex) JavaScript, Python, Ruby 등..

그러면, 타입스크립트는 어떤 타입 시스템일까요?

타입스크립트는 정적 타임 시스템과 동적 타입 시스템의 장점을 모두 추구하는 독특한 시스템입니다.

저는 이전에 정적 타입 시스템이라고 생각했어요. 동적언어와 정적언어 둘중 하나만 고른다고 생각하면 정적 언어이기 때문이라고 생각했는데 독특한 시스템을 가지고 있다는 말에 뭔가 신기했습니다! 🧐

이 독특한 시스템인 이유는 다음과 같아요.

  • 실행 전에 타입을 검사할 수 있는 정적 타입 시스템을 제공합니다.
  • 그러나 기존 자바스크립트처럼 자유로운 코딩 스타일도 유지가 가능합니다.

타입스크립트는 어떻게 실행될까?

TypeScript는 우리가 작성한 코드를 내부적으로 AST(Abstract Syntax Tree, 추상 구문 트리)로 변환한 뒤, 해당 AST를 기반으로 타입 검사를 수행합니다. 이 과정에서 타입 오류가 발견되면 컴파일은 중단됩니다.

문제가 없다면 TypeScript는 코드를 JavaScript로 트랜스파일(transpile) 하며, 이후 실행은 일반 JavaScript와 동일하게 브라우저나 Node.js 런타임에서 AST → 바이트코드 → 실행 흐름을 따르게 됩니다.

즉, TypeScript 자체는 실행 환경이 아닌 정적 타입 검사기 + 트랜스파일러의 역할을 하며, 실행은 결국 JavaScript가 담당하게 되는 구조입니다.

특징

  1. 변수 선언 시 값을 초기화하면 타입스크립트가 자동으로 타입을 추론합니다. -> 모든 변수에 타입을 명시할 필요 없습니다.
  2. 필요한 경우에는 명시적으로 타입을 지정할 수 있습니다.
    이러한 특징을 점진적 타입 시스템이라고 부릅니다.

Day 2️⃣

둘째 날은 타입스크립트의 스코프와 기본 타입 이해하기의 주제에 가깝다고 생각 돼요.
다음과 같이 정리해봤습니다!

타입스크립트의 파일 스코프

타입스크립트는 기본적으로 각 파일을 전역 스코프(global scope)로 인식합니다.

// index.ts
const a = 1;

// hello.ts
const a = 1;

위와 같이 작성하면, 두 파일 모두 전역 스코프에서 a라는 동일한 이름의 변수를 선언한 것으로 간주됩니다.

이로 인해 변수 중복 오류가 발생합니다.

그러면 전역 → 개별 모듈로 만들기 (모듈 스코프) 방법은?

타입스크립트에서 파일을 모듈(Module)로 인식시키려면 아래 방법을 사용합니다

1️⃣ export/import 사용하기

  • 파일 내에 export 또는 import 구문이 존재하면, 해당 파일은 자동으로 모듈 스코프로 전환됩니다.
  • 각 파일의 스코프가 독립적으로 격리되므로 변수 중복 문제가 발생하지 않습니다.

2️⃣ moduleDetection 옵션 사용하기

  • tsconfig.json 파일에 moduleDetection 옵션을 설정하면, 타입스크립트가 보다 적극적으로 모듈을 감지합니다.
  • 예를들어
{
  "compilerOptions": {
    "moduleDetection": "force"
  }
}

이 설정을 사용하면 명시적인 export 없어도 모듈 스코프로 인식시킬 수 있습니다. (단, 프로젝트 설정에 따라 권장여부는 달라질 수 있습니다.)

원시 타입 (Primitive Types)

타입설명예시
number숫자let age: number = 30;
string문자열let name: string = "John";
boolean참/거짓let isAdmin: boolean = true;
null값 없음let data: null = null;
undefined정의되지 않음let value: undefined = undefined;
symbol고유하고 변경 불가능한 값let sym: symbol = Symbol("key");
bigint매우 큰 정수let big: bigint = 9007199254740991n;

리터럴(Literal)

리터럴(Literal)은 값 그 자체 를 의미합니다

let a: 1; // a 변수는 오직 1이라는 값만 가질 수 있음
let b: "hello"; // b 변수는 오직 "hello"라는 문자열만 가질 수 있음
  • 리터럴 타입은 특정 값만을 허용하는 타입입니다.
  • 주로 유니언 타입, 상수 값 제한 등에 활용됩니다!

Day 3️⃣

셋째 날은 객체 리터럴 타입과 다양한 객체 타입 패턴들에 대한 주제입니다.

객체 리터럴타입

TypeScript에서는 객체를 사용할 때, 객체의 속성(property)들과 그 타입을 명시적으로 선언하여 정적 타입 안정성을 확보할 수 있습니다.
아래는 객체 리터럴 타입을 직접 선언해서 객체를 정의한 예시입니다.

let user: {
  id: number;
  name: string;
} = {
  id: 1,
  name: "김범수",
};

⚙️ 구조적 타입 시스템

  • 타입스크립트는 구조를 기준으로 타입을 판단합니다.
  • 이처럼 구조를 기반으로 하는 타입 시스템을 구조적 타입 시스템(Structural Type System) 이라고 부릅니다.
  • 또한, 속성(Property)을 중심으로 타입을 정의하기 때문에 Property-Based Type System 이라고도 불립니다.

참고:
C언어나 Java는 타입의 이름(name)을 기준으로 판단하는
명목적 타입 시스템(Nominal Type System)
을 사용합니다.

🔒 readonly 키워드

절대 수정되어서는 안 되는 값에는 readonly를 붙여서 불변성을 보장할 수 있습니다.

let config: {
  readonly apiKey: string;
} = {
  apiKey: "MY_API_KEY",
};

config.apiKey = "HACKED"; // ❌ 오류 발생: 읽기 전용 속성입니다.

🏷️ 타입 별칭 (Type Alias)

type User = {
  id: number;
  name: string;
};

let user: User = {
  id: 1,
  name: "이정환",
};
  • 타입 별칭은 컴파일 이후 JavaScript 코드에는 존재하지 않습니다.
  • 전적으로 개발 단계에서만 사용되는 문법

🔑 인덱스 시그니처 (Index Signature)

  • key와 value의 패턴을 정의하여 객체의 타입을 설정할 수 있는 문법
type CountryCodes = {
  Korea: string;
  UnitedStates: string;
};

let countryCodes = {
  Korea: "ko",
  UnitedStates: "us",
};

하지만 나라가 수십 개라면? 전부 작성하기 어렵습니다.

type CountryCodes = {
  [key: string]: string;
};

let codes: CountryCodes = {
  Korea: "ko",
  UnitedStates: "us",
  France: "fr",
};

유의사항

  • 인덱스 시그니처를 사용하면, 명시적으로 지정한 속성들도 인덱스 시그니처의 value 타입과 일치하거나 호환해야 합니다.
type InvalidCodes = {
  [key: string]: number;
  Korea: string; // ❌ 오류! string은 number와 호환되지 않음
};

📚 enum 타입

  • 여러 값을 열거해 이름을 붙여주는 방식입니다.
enum Direction {
  Up,
  Down,
  Left,
  Right,
}

let d: Direction = Direction.Up;
  • 기본적으로 숫자형 enum이며, 0부터 자동으로 값이 부여됩니다
console.log(Direction.Up);    // 0
console.log(Direction.Down);  // 1
  • 명시적으로 시작 숫자를 지정할 수도 있습니다:
enum Status {
  Success = 200,
  NotFound = 404,
  ServerError = 500,
}

Day 4️⃣

Day 4는 any, unknown, void, never 같은 특수 타입들을 중심으로 타입의 안전성과 계층 구조에 대해 다룬 날이었습니다! 🍀

🧨 any 타입

특정 변수의 타입을 우리가 확실히 모를때 사용합니다. (치트키)

let value: any;

value = 1;
value = "hello";
value = true;
value = [1, 2, 3];
  • 타입 검사를 완전히 비활성화합니다.
  • 다른 어떤 타입에도 자유롭게 할당 가능하고, 연산도 가능합니다.
  • 하지만 런타임 오류 가능성이 크기 때문에 최후의 수단으로만 사용해야 합니다.

🔒 unknown 타입

모든 값을 담을 수 있지만, 사용은 제한적

let value: unknown;

value = 1;
value = "hello";
// value + 1; ❌ 연산 불가능

if (typeof value === "number") {
  console.log(value + 1); // ✅ 조건부 타입 검사 후 사용 가능
}
  • any와 비슷하게 모든 값을 할당할 수 있지만, 실제 사용할 땐 타입을 좁히는 과정이 필요합니다.
  • 타입 안정성이 높아 any보다 훨씬 안전합니다.

✅ 권장되는 타입: 모르는 값을 처리할 때는 any보다 unknown을 사용하세요.

🕳️ void 타입

"void -> 공허 -> 아무것도 없다."

"아무것도 반환하지 않음"을 의미하는 타입"

  • 주로 return을 하지 않는 함수에 사용

  • undefined를 할당할 수 있고,

  • null도 가능하지만 strictNullChecks가 꺼져 있어야 함

🛑 never 타입

존재하지 않는 불가능한 타입, 절대 발생할 수 없는 값

function error(): never {
  throw new Error("에러 발생!");
}

function infinite(): never {
  while (true) {}
}

undefined, null도 할당할 수 없음

any도 never에 할당할 수 없음

어떤 타입에도 할당 가능하지만, 반대로는 불가능

🧠 타입스크립트를 이해한다는 것?

타입스크립트를 단순히 "타입을 붙이는 언어"라고 생각하면 한계가 있습니다.
정말로 이해하려면 아래 세 가지 기준을 중심으로 봐야 합니다.

  1. 어떤 기준으로 타입을 정의하는가?

  2. 어떤 기준으로 타입 간의 관계를 정의하는가?

  3. 어떤 기준으로 타입 오류를 검출하는가?

타입 호환성

  • 한 타입을 다른 타입으로 취급해도 괜찮은가?

  • number 리터럴 타입은 number타입에 호환된다

  • number type은 number 리터럴 타입에 호환되지 않는다.
    예를 들면, number타입이 직사각형, number 리터럴 타입이 정사각형 이라고 생각하자!

let num1: number = 10;
let num2: 10 = 10;

num1 = num2; // ✅ 업캐스팅 (서브 → 슈퍼)
num2 = num1; // ❌ 다운캐스팅 (슈퍼 → 서브)

서브(sub)타입을 슈퍼(super)타입에 취급하는 것을 업캐스팅이라고 합니다.
반대로, 슈퍼(super)타입에 서브(sub)타입에 가면 다운캐스팅이라고 합니다.

타입계층도를 보면 이해가 잘 되는 것 같습니다!

📌 업캐스팅은 안전하지만, 다운캐스팅은 런타임 위험을 수반

업 캐스팅으로 unknown에 할당을 할 순 있지만 다운캐스팅으로 서브(sub)에 할당을 할 수 없습니다!

never 타입(공집합)

never타입은 모든 타입에 서브타입이기때문에 어느 타입에든 할당이 가능.

function neverFunc() : never {
    while(true) {}
}

let num: number = neverFunc() ok
let str: string = neverFunc() ok
let bool: boolean = neverFunc() ok

반대로 다운 캐스팅으로도 안된다. 어떠한 값도 저장할 수 없다.

🧨 다시 보는 any

any는 타입 계층도 자체를 무시하는 특이한 존재입니다.
모든 타입에 슈퍼(super)타입에 위치하기도 하고 모든 타입에 서브(sub)타입이기도 합니다.

하지만, anynever타입에 다운 캐스팅을 할 수 없습니다!!!

타입특징안전성
any아무 값이나 할당 가능, 타입 검사 없음❌ 매우 낮음
unknown아무 값이나 할당 가능, 사용은 제한됨✅ 높음
void반환값 없음✅ 적절한 용도에 사용 시 안전
never어떤 값도 할당 불가, 도달 불가능한 코드✅ 타입 안전 보장

Day 5️⃣

Day 5는 구조적 타입 호환성과 유니언/인터섹션 타입의 차이, 타입 추론이 중심이었습니다! 🔥

🧩 객체 타입 간의 호환성 - 어떤 객체 타입을 다른 객체 타입으로 취급해도 괜찮은가?

위에서 언급드렸지만 타입스크립트에서는 객체의 구조(프로퍼티) 를 기준으로 타입 간의 호환성을 판단합니다.

이를 구조적 타입 시스템(Structural Typing) 이라고 합니다.

// 슈퍼타입
type Animal = {
  name: string;
  color: string;
};

// 서브타입
type Dog = {
  name: string;
  color: string;
  breed: string;
};

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

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

animal = dog; // ✅ OK: Dog는 Animal의 모든 속성을 포함하므로 업캐스팅
dog = animal; // ❌ Error: breed 속성이 없기 때문에 다운캐스팅은 불가

⚖️ 유니언 타입 (Union)

여러 타입 중 하나만 만족하면 되는 타입

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

type Designer = {
  name: string;
  tool: string;
};

type Union1 = Developer | Designer;


let union1: Union1 = {
  name: "이정환",
  language: "TypeScript",
}; // ✅ Developer 만족

let union2: Union1 = {
  name: "이정환",
  tool: "Figma",
}; // ✅ Designer 만족

let union3: Union1 = {
  name: "이정환",
  language: "TypeScript",
  tool: "Figma",
}; // ✅ 둘 다 만족해도 괜찮음

let union4: Union1 = {
  name: "이정환",
}; // ❌ Error: Developer도, Designer도 모두 만족하지 못함

🔗 교집합 타입 (Intersection)

let variable: number & string;

type Dog = {
    name: string;
    color: string;
}

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

type Intersection = Dog & Person;

let intersection1: Intersection = {
    name: "",
    color: "",
    language: ""
}

let intersection1: Intersection = {
  name: "돌돌이",
  color: "brown",
  language: "Korean",
}; // ✅ 모든 속성 충족

🤖 타입 추론 (Type Inference)

타입스크립트는 대부분의 경우 타입을 자동으로 추론합니다.

변수 선언 시

let a = 10; // 🔍 a: number 로 추론됨
const b = 10; // 🔍 b: 10 (리터럴 타입) 으로 추론됨

let은 변수이므로 일반 타입(number 등) 으로 추론!

const는 재할당이 불가능하므로 리터럴 타입(고정값) 으로 추론!

대부분의 경우 명시적 타입 선언 없이도 정확하게 추론되므로
불필요하게 타입을 반복하지 않아도 됩니다.

개념설명특징
객체 타입 호환성구조 기준으로 타입 호환 판단프로퍼티가 더 많은 쪽이 더 적은 쪽으로 할당 가능
유니언 타입 (``)여러 타입 중 하나만 만족하면 됨OR 조건
인터섹션 타입 (&)여러 타입 모두 만족해야 함AND 조건
타입 추론타입을 명시하지 않아도 자동으로 추론됨const는 리터럴, let은 일반 타입

Day 6️⃣

Day 6는 타입 단언(as, as const, !), 타입 좁히기, 그리고 서로소 유니온을 중심으로, 타입스크립트에서 ‘타입을 확정짓는 방법’에 대해 다루었습니다! 🔥

🧱 타입 단언(Type Assertion)

타입 단언이란, 개발자가 타입스크립트에게
“이 값은 내가 알고 있는 이 타입이 맞아!”라고 직접 말해주는 문법입니다.

const value = someValue as SomeType;

A가 B의 슈퍼 타입 이거나 A가 B의 서브타입이어야 합니다.

let num1 = 10 as never;     // ✅ 가능 (number는 never의 슈퍼타입)
let num2 = 10 as unknown;   // ✅ 가능 (unknown은 모든 타입의 슈퍼타입)
let num3 = 10 as string;    // ❌ 에러 (number와 string은 호환되지 않음)

🔒 const 단언

let num = 10 as const;
// num: 10 (number가 아니라 리터럴 타입)

let arr = [1, 2, 3] as const;
// arr: readonly [1, 2, 3]
  • 값을 수정할 수 없는 상수로 간주
  • 배열/객체는 자동으로 readonly 속성 부여

🚫 Non-Null 단언

옵셔널 체이닝(?.)에서 null 또는 undefined가 절대 아님을 보장하고 싶을 때 ! 사용합니다.

type Post = {
  title: string;
  author?: string;
};

let post: Post = {
  title: "게시글 1",
  author: "이정환",
};

const len: number = post.author!.length;
// `!` 덕분에 author는 절대 null이 아니라고 단언
  • 📌 타입 검사기를 속이는 방식이기 때문에, 실제로 null일 가능성이 없을 때만 사용해야 합니다.

타입 좁히기 (Type Narrowing) - 조건문 등을 활용해 넓은 타입을 더 구체적인 타입으로 좁히는 과정

function process(value: number | string | Date) {
  if (typeof value === "number") {
    console.log(value.toFixed()); // number로 좁혀짐
  } else if (typeof value === "string") {
    console.log(value.toUpperCase()); // string으로 좁혀짐
  } else if (value instanceof Date) {
    console.log(value.getFullYear()); // Date로 좁혀짐
  }
}

🧬 서로소 유니온 타입 (Discriminated Union)

교집합이 없는 유니온 타입을 구성하고, 공통된 식별자(tag)를 기준으로 조건 분기하는 패턴

type LoadingTask = {
  state: "LOADING";
};

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

type SuccessTask = {
  state: "SUCCESS";
  data: {
    result: string;
  };
};

type AsyncTask = LoadingTask | FailedTask | SuccessTask;

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.data.result);
      break;
  }
}

const loading: AsyncTask = {
  state: "LOADING",
};

const failed: AsyncTask = {
  state: "FAILED",
  error: {
    message: "오류 발생 원인은 ~",
  },
};

const success: AsyncTask = {
  state: "SUCCESS",
  data: {
    result: "정상적으로 완료되었습니다",
  },
};
개념설명
as 단언값의 타입을 강제로 지정
as const값을 리터럴 타입 + readonly로 고정
! (non-null 단언)null 또는 undefined가 아님을 단언
타입 좁히기조건문 등을 활용해 타입을 구체화
서로소 유니온state처럼 구분 가능한 값을 통해 타입 분기 처리

Day 7️⃣

Day 7은 함수 타입을 어떻게 정의하고, 서로 다른 함수 타입 간에 호환 가능한지를 판단하는 기준에 대해 다루었습니다! 🔥

함수 타입 정의

함수를 설명하는 가장 명확한 방법은 어떤 매개변수를 받고, 어떤 값을 반환하는지를 명시하는 것입니다.

// 함수를 설명하는 가장 좋은 방법
// js. 어떤 매개변수를 받고, 어떤 결과값을 반환하는지
// ts. 어떤 [타입의] 매개변수를 받고, 어떤 [타입의] 결과값을 반환하는지 이야기

function func(a: number, b: number): number {
  return a + b;
}

함수 타입 표현식

type Add = (a: number, b: number) => number;

const add: Add = (a, b) => a + b;
  • 위와 같은 형태를 함수 타입 표현식(Function Type Expression) 이라고 부릅니다.
  • 함수의 매개변수와 반환 타입을 명확히 선언

호출 시그니처 (콜 시그니처)

type Operation = {
  (a: number, b: number): number;
};

const add: Operation = (a, b) => a + b;

왜 객체 타입처럼 정의하는걸까?

  • 자바스크립트 함수가 객체이기 때문이다.
  • 함수는 사실 객체이기 때문에, 함수 자체를 객체의 형태로 정의할 수 있습니다.
  • 이러한 구조를 호출 시그니처(call signature)

함수 타입 호환성

특정 함수 타입을 다른 함수 타입으로 취급해도 괜찮은가를 판단하는 기준!

  1. 반환값의 타입이 호환되는가?
  2. 매개변수의 타입이 호환되는가?

1️⃣ 반환값의 타입이 호환되는가?

type A = () => number;
type B = () => 10;

let a: A = () => 10;
let b: B = () => 10;

a = b; // ✅ 업캐스팅 (리터럴 → 일반 타입)
b = a; // ❌ 다운캐스팅 (일반 → 리터럴)

리터럴 타입은 일반 타입에 할당 가능하지만, 그 반대는 다운캐스팅이므로 허용되지 않음

2️⃣ 매개변수의 타입이 호환되는가?

// 매개변수의 개수가 같을 때
type C = (value: number) => void;
type D = (value: 10) => void;

let c: C = (value) => {};
let d: D = (value) => {};

c = d; // ❌
d = c; // ✅
// 매개변수는 반대 방향입니다!
// 반환값: 서브 → 슈퍼 가능 (업캐스팅 가능)
// 매개변수: 슈퍼 → 서브 가능만 허용 (즉, 다운캐스팅만 허용)


type Animal = { name: string };
type Dog = { name: string; color: string };

let animalFunc = (animal: Animal) => {
  console.log(animal.name);
};

let dogFunc = (dog: Dog) => {
  console.log(dog.name);
  console.log(dog.color);
};

animalFunc = dogFunc; // ❌
dogFunc = animalFunc; // ✅

매개변수가 많고 구체적일수록 더 좁은 타입입니다.
좁은 매개변수를 넓은 쪽으로 넣을 수는 있지만 그 반대는 위험합니다.

이렇게 된다고 가정하면

let testFunc = (animal: Animal) =>{
    console.log(animal.name)
    console.log(animal.color) // 말이 안되는 상황이 나오기 때문이다.
}
// 매개변수 갯수가 같을 때 함수타입의 호환성은 A(슈퍼) <- B(서브) 이땐 업캐스팅이 안된다

- 매개변수의 개수가 다를 때
type Func1 = (a: number, b: number) => void;
type Func2 = (a: number) => void;

let func1: Func1 = (a, b) => {};
let func2: Func2 = (a) => {};

func1 = func2; // ✅ 호출 시 두 번째 매개변수를 무시해도 되므로 가능
func2 = func1; // ❌ 호출 시 b 값이 없으면 에러

타입스크립트의 함수 타입 호환성은
실제 실행 환경에서 문제가 생기지 않도록 보장하기 위한 타입 설계 원칙입니다.

Day 1️⃣ ~ Day 7️⃣ 까지의 여정..

Day 1부터 Day 7까지의 학습을 정리하면서, 단순히 문법을 익히는 것을 넘어
타입이 어떻게 동작하고, 어떤 상황에서 어떤 타입을 선택해야 하는지에 대한 판단 기준이 생기기 시작했습니다.

개념을 글로 풀어내는 과정 자체가 복습이자 사고의 확장이었고,
실무에서 겪었던 모호함들이 차츰 명확해지는 느낌이 들었습니다.

정리하다 보니 분량이 상당히 길어져서,
나머지 Day 8부터 14까지의 내용은 다음 포스팅에서 이어서 공유드리겠습니다.

끝까지 읽어주셔서 감사합니다 🙇‍♂️

강의: 한 입 크기로 잘라먹는 Next.js(v15)
타입 계층도 이미지 출처: 한 입 크기로 잘라먹는 타입스크립트(TypeScript)

profile
실패를 두려워하지 않고 끊임없이 시도하는 프론트엔드 개발자입니다.

0개의 댓글