[TypeScript-09] 조건부 타입, infer, d.ts 파일, implements, keyof, Mapped Types

Comely·2025년 6월 6일

TypeScript

목록 보기
9/9

1. 조건부 타입 (Conditional Types)

삼항연산자 기본 개념

JavaScript에서 사용하는 조건부 연산자를 TypeScript 타입에서도 활용 가능합니다.

// JavaScript 삼항연산자
조건문 ? 참일때실행할코드 : 거짓일때실행할코드
3 > 1 ? console.log('맞아요') : console.log('아님')

TypeScript 조건부 타입

type Age<T> = T extends string ? string : unknown;

let age: Age<string>;   // string 타입
let age2: Age<number>;  // unknown 타입

핵심: extends 키워드로 조건을 만들고, 삼항연산자로 결과 타입을 지정합니다.

실용적인 예제

type FirstItem<T> = T extends any[] ? T[0] : any;

let age1: FirstItem<string[]>;  // string 타입
let age2: FirstItem<number>;    // any 타입

2. infer 키워드

기본 문법

조건부 타입에서 타입을 추출하여 변수로 사용할 수 있는 키워드입니다.

type Person<T> = T extends infer R ? R : unknown;
type 새타입 = Person<string>;  // string 타입

배열 타입 추출

type 타입추출<T> = T extends (infer R)[] ? R : unknown;
type NewType = 타입추출<boolean[]>;  // boolean 타입

함수 Return 타입 추출

type 타입추출<T> = T extends (() => infer R) ? R : unknown;
type NewType = 타입추출<() => number>;  // number 타입

참고: ReturnType<> 내장 타입으로도 함수의 return 타입 추출 가능합니다.

3. declare 키워드와 외부 파일 연동

declare 키워드 사용법

외부 JavaScript 파일의 변수를 TypeScript에서 사용할 때 타입 에러를 방지합니다.

// data.js
var a = 10;
var b = {name: 'kim'};

// index.ts
declare let a: number;
console.log(a + 1);  // 에러 없이 사용 가능

특징:

  • declare가 붙은 코드는 JavaScript로 변환되지 않음
  • 컴파일러에게 힌트를 주는 역할

Ambient Module

TypeScript의 특별한 기능으로, import/export 없이도 같은 폴더의 타입을 전역으로 사용 가능합니다.

// data.ts
type Age = number;
let 나이: Age = 20;

// index.ts (import 없이 사용 가능)
console.log(나이 + 1);   // 가능
let 철수: Age = 30;      // 가능

Global 모듈 만들기

// 로컬 모듈에서 전역 타입 선언
declare global {
  type Dog = string;
}

4. d.ts 파일 활용

d.ts 파일이란?

  • Definition의 약자로 타입 정의만 저장하는 파일
  • JavaScript로 컴파일되지 않음
  • 타입 정의 전용 파일

타입 정의 파일 만들기

// types.d.ts
export type Age = number;
export type multiply = (x: number, y: number) => number;
export interface Person { name: string }

자동 생성 설정

// tsconfig.json
{
  "compilerOptions": {
    "declaration": true
  }
}

이 설정으로 .ts 파일 저장 시 자동으로 .d.ts 파일이 생성됩니다.

외부 라이브러리 타입 설치

npm install --save @types/jquery

5. implements 키워드

기본 사용법

클래스가 특정 인터페이스의 구조를 갖고 있는지 확인하는 키워드입니다.

interface CarType {
  model: string;
  price: number;
}

class Car implements CarType {
  model: string;
  price: number = 1000;
  constructor(a: string) {
    this.model = a;
  }
}

implements vs extends

  • implements: 구조 확인만 (타입 할당 안됨)
  • extends: 상속 (속성과 메서드 복사)
class Car implements CarType {
  model;  // any 타입 (implements는 타입 할당 안함)
  // ...
}

6. Index Signatures

기본 문법

객체의 모든 속성에 대한 타입을 한 번에 지정하는 방법입니다.

interface StringOnly {
  [key: string]: string;
}

let obj: StringOnly = {
  name: 'kim',
  age: '20',        // 모든 값이 string이어야 함
  location: 'seoul'
};

다른 속성과 함께 사용

interface StringOnly {
  age: string;                    // 특정 속성 지정
  [key: string]: string;          // 나머지 모든 속성
}

숫자 키 사용

interface StringOnly {
  [key: number]: string;
}

let obj: StringOnly = {
  0: 'kim',
  1: '20',
  2: 'seoul'
};

Recursive Index Signatures

중첩된 객체를 위한 재귀적 타입 정의입니다.

interface MyType {
  'font-size': MyType | number;
}

let obj: MyType = {
  'font-size': {
    'font-size': {
      'font-size': 14
    }
  }
};

7. keyof 연산자와 Mapped Types

keyof 연산자

객체 타입의 모든 키를 union type으로 추출합니다.

interface Person {
  age: number;
  name: string;
}

type PersonKeys = keyof Person;  // "age" | "name"

Mapped Types

기존 타입의 모든 속성을 다른 타입으로 변환하는 타입 변환기입니다.

type Car = {
  color: boolean;
  model: boolean;
  price: boolean | number;
};

type TypeChanger<MyType> = {
  [key in keyof MyType]: string;
};

type 새로운타입 = TypeChanger<Car>;
// { color: string; model: string; price: string; }

범용 타입 변환기

type TypeChanger<MyType, T> = {
  [key in keyof MyType]: T;
};

type NewBus = TypeChanger<Bus, boolean>;    // 모든 속성이 boolean
type NewBus2 = TypeChanger<Bus, string[]>;  // 모든 속성이 string[]

8. 실무 예제

숙제 1: 조건부 타입

type Age<T> = T extends [string, ...any] ? T[0] : unknown;

let age1: Age<[string, number]>;   // string
let age2: Age<[boolean, number]>;  // unknown

숙제 2: infer로 함수 파라미터 추출

type 타입뽑기<T> = T extends (x: infer R) => any ? R : any;
type a = 타입뽑기<(x: number) => void>;  // number

숙제 3: Index Signatures 활용

// 자동차 정보 타입
interface CarInfo {
  [key: string]: string | number;
}

// 중첩 객체 타입
interface MyType {
  'font-size': number;
  [key: string]: number | MyType;
}

숙제 4: Mapped Types 활용

// Bus 타입 변환
type Bus = {
  color: string;
  model: boolean;
  price: number;
};

type TypeChanger<MyType> = {
  [key in keyof MyType]: string | number;
};

type NewBus = TypeChanger<Bus>;

정리

조건부 타입 & infer

  • 목적: 타입 파라미터에 따라 다른 타입 반환
  • 방법: extends와 삼항연산자, infer로 타입 추출

declare & d.ts

  • 목적: 외부 JavaScript 파일과의 연동, 타입 정의 분리
  • 방법: declare로 타입 힌트, .d.ts로 타입 정의 파일

Index Signatures & Mapped Types

  • 목적: 동적 객체 타입 정의, 타입 변환
  • 방법: [key: type]: type 문법, keyofin 연산자
profile
App, Web Developer

0개의 댓글