TypeScriptTypeScript 기초 · 3기초

인터페이스와 타입 별칭 — 복잡한 구조 정의하기

TypeScriptinterfacetype유니온인터섹션

인터페이스 (Interface)

객체의 구조(형태)를 정의합니다.

interface User {
    id: number;
    name: string;
    email: string;
}

const user: User = {
    id: 1,
    name: "철수",
    email: "kim@example.com",
};

// ❌ 오류: email 누락
const user2: User = {
    id: 2,
    name: "영희",
};

선택적 속성과 읽기 전용

interface UserProfile {
    id: number;
    name: string;
    email?: string;         // 선택적 (optional)
    readonly createdAt: Date; // 읽기 전용
    bio?: string;
}

const profile: UserProfile = {
    id: 1,
    name: "철수",
    createdAt: new Date(),
};

profile.name = "영희";      // ✅
// profile.createdAt = new Date();  // ❌ 읽기 전용

인터페이스 확장

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

interface Dog extends Animal {
    breed: string;
    speak(): string;
}

const dog: Dog = {
    name: "바둑이",
    age: 3,
    breed: "진돗개",
    speak: () => "멍멍!",
};

// 여러 인터페이스 확장
interface Pet extends Animal, Dog {
    owner: string;
}

타입 별칭 (Type Alias)

type 키워드로 타입에 이름을 붙입니다.

type ID = string | number;
type Point = { x: number; y: number };
type Callback = (error: Error | null, result: string) => void;

// 사용
const userId: ID = "user-123";
const pos: Point = { x: 10, y: 20 };

interface vs type: 차이점

// interface: 동일 이름으로 선언 병합 가능
interface Window {
    title: string;
}
interface Window {
    location: string;  // 자동으로 병합됨
}

// type: 재선언 불가 → 명확성이 장점
type Point = { x: number };
// type Point = { y: number };  // ❌ 중복 식별자

// 확장
interface Animal { name: string }
interface Dog extends Animal { breed: string }  // interface 확장

type Animal2 = { name: string };
type Dog2 = Animal2 & { breed: string };  // 인터섹션으로 확장

실무 가이드: 객체 구조는 interface, 유니온·인터섹션·원시 타입 조합은 type 사용.


유니온 타입 (Union)

여러 타입 중 하나를 허용합니다.

type StringOrNumber = string | number;

function display(value: string | number): string {
    if (typeof value === "string") {
        return value.toUpperCase();
    }
    return value.toFixed(2);
}

// 리터럴 유니온
type Direction = "north" | "south" | "east" | "west";
type StatusCode = 200 | 404 | 500;

function handleStatus(code: StatusCode): string {
    if (code === 200) return "성공";
    if (code === 404) return "찾을 수 없음";
    return "서버 오류";
}

인터섹션 타입 (Intersection)

여러 타입을 모두 만족해야 합니다.

interface Timestamped {
    createdAt: Date;
    updatedAt: Date;
}

interface SoftDelete {
    deletedAt?: Date;
}

type BaseEntity = Timestamped & SoftDelete;

interface User extends BaseEntity {
    name: string;
    email: string;
}

const user: User = {
    name: "철수",
    email: "kim@example.com",
    createdAt: new Date(),
    updatedAt: new Date(),
};

인덱스 시그니처

동적 키를 가진 객체 타입을 정의합니다.

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

const translations: StringMap = {
    hello: "안녕",
    bye: "안녕히",
    thanks: "감사합니다",
};

// 특정 키와 인덱스 시그니처 혼합
interface Config {
    mode: "dev" | "prod";       // 고정 키
    [key: string]: unknown;     // 나머지 동적 키
}

정리

개념문법특징
interfaceinterface Foo { }선언 병합, 확장 (extends)
type aliastype Foo = { }유니온·인터섹션·원시 타입 가능
선택적 속성prop?: Type있어도 없어도 됨
읽기 전용readonly prop: Type할당 후 변경 불가
유니온A | BA 또는 B
인터섹션A & BA와 B 모두

다음 편에서는 함수와 제네릭 — 재사용 가능한 타입 안전 함수를 만드는 방법을 배웁니다.

궁금한 점이 있으신가요?

협업·의뢰는 아래로, 가벼운 소통은 인스타그램 @bluefox._.hi도 환영이에요.