본문 바로가기

Front-end/Javascript

[TypeScript] 핵심 고급 문법 - 제네릭 / keyof연산자 / Mapped Types (매핑된 타입) / Conditional Types (조건부 타입)

 

타입스크립트를 보다가 한줄의 문법을 보게되었는데 잘 모르는 부분이 있어서 정리를 하게되었다.

해당 문법은 타입스크립트를 제대로 공부하지않은 나에게는 고급문법이었고 해석이 필요해서 하나씩 구체적으로 정리하게되었다.

  type FunctionKeys<T> = {
    [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
  }[keyof T];

 

 

✅ 제네릭

위에서 T는 타입 매개변수(Generic Type)이다.

 

  • 함수나 타입을 선언할 때 타입을 변수처럼 받아서 재사용 가능하게 하는 문법.
  • T는 “아직 어떤 타입이 올지 모르는” 타입 매개변수.

 

FunctionKeys<T> 

즉, FunctionKeys를 쓸 때 실제 타입을 넘겨주는거다.

예시로 한번 보면 

 

type Example = {
  id: number;
  name: string;
  login: (u: string, p: string) => Promise<boolean>;
  logout: () => void;
};

type FnKeys = FunctionKeys<Example>;

 

여기서 T는 바로 Example 타입

 

 

✅ keyof 연산자

객체 타입의 모든 속성 이름(key) 을 문자열 리터럴 유니언으로 추출하는 연산자.

만약 위에 같은 경우는 다음과 같이 나온다

"id" | "name" | "login" | "logout"

 

 

그리고 다른 예시를 든다면 

type Example = { id: number; name: string; };
type Keys = keyof Example; // "id" | "name"

 

즉 객체 타입의 모든 속성 이름(key) 을 문자열 리터럴 유니언으로 추출하는 연산자

 

✅ Mapped Types (매핑된 타입)

type 선언문 안에서 [K in keyof T] 형태로,
기존 타입의 모든 속성을 순회하면서 새 타입을 만드는 문법

반복문느낌!

type ReadonlyType<T> = {
  [K in keyof T]: T[K];
}

 

  [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;

 

위에를 보면 

✅Conditional Types (조건부 타입) 

뜻은 👉

“T[K]가 함수 타입인지 확인해라”

구체적으로

  • (...args: any[]) => any
    → “매개변수를 아무거나 받아서, 어떤 값(any)을 반환하는 함수 타입”
    → 즉, 함수 모양이면 전부 매칭됨.
  • extends (...args: any[]) => any
    → T[K]가 함수 타입이면 true, 아니면 false로 평가

그래서 함수면 K  아니면 never로 새로운형태로만들어진다

 

K T[K] extends 함수? 결과

id number never
name string never
login function "login"
logout function "logout"

 

 

결과는 이렇게 나온다.

{
  id: never;
  name: never;
  login: "login";
  logout: "logout";
}

 

그이후에

 

 TypeScript의 “유니언에서의 never 제거 규칙” 때문에 login과 logout만 남게된다.


🧠 규칙:

TypeScript에서는 never는 “존재하지 않는 타입”, 즉 공집합(∅)과 같아요.
따라서 A | never === A 로 단순화됩니다.

 

 

 

 

 

✅ Indexed Access Types (인덱스 접근 타입)

T[K] — 객체 타입 T의 속성 K의 타입을 참조.

 

type User = { id: number; name: string; };
type NameType = User["name"]; // string