개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

Interface — 객체의 형태를 정의하는 계약

2025년 11월 12일
TypeScriptInterface타입객체

여러 곳에서 사용자 정보를 다루는 코드를 작성한다고 가정합니다. 어떤 곳에서는 user.name을, 어떤 곳에서는 user.username을 씁니다. 오타가 있어도 런타임 전까지 알기 어렵습니다. Interface는 이 문제를 해결합니다. 객체가 어떤 프로퍼티를 가져야 하는지 한 곳에 정의해두면, 어긋난 사용을 즉시 잡아낼 수 있습니다.

Interface 기본 문법

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

const user: User = {
  name: "철수",
  age: 30,
  email: "chulsoo@example.com",
};

// 프로퍼티가 빠지면 오류
const incomplete: User = {
  name: "영희",
  // 오류: 'age', 'email' 프로퍼티가 없습니다
};

선택적 프로퍼티

?를 붙이면 있어도 되고 없어도 되는 프로퍼티가 됩니다.

interface User {
  name: string;
  age: number;
  bio?: string; // 있어도 되고 없어도 됨
}

const user1: User = { name: "철수", age: 30 };          // 정상
const user2: User = { name: "영희", age: 25, bio: "안녕" }; // 정상

bio를 사용할 때는 undefined일 수 있으므로, 존재 여부를 확인하고 사용합니다.

if (user1.bio) {
  console.log(user1.bio.toUpperCase());
}

읽기 전용 프로퍼티

readonly를 붙이면 최초 할당 이후 변경할 수 없습니다.

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

const user: User = { id: 1, name: "철수" };
user.name = "영희"; // 정상
user.id = 2;        // 오류: 읽기 전용 프로퍼티에 할당할 수 없습니다

메서드 정의

함수도 프로퍼티로 정의할 수 있습니다.

interface Calculator {
  add(a: number, b: number): number;
  subtract(a: number, b: number): number;
}

const calc: Calculator = {
  add(a, b) { return a + b; },
  subtract(a, b) { return a - b; },
};

Interface 확장

extends로 다른 Interface를 상속받아 확장합니다.

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

interface Dog extends Animal {
  breed: string;
}

const dog: Dog = {
  name: "뭉치",
  age: 3,
  breed: "골든 리트리버",
};

여러 Interface를 동시에 확장하는 것도 가능합니다.

interface Flyable {
  fly(): void;
}

interface Swimmable {
  swim(): void;
}

interface Duck extends Animal, Flyable, Swimmable {
  quack(): void;
}

선언 병합

같은 이름의 Interface를 여러 번 선언하면 자동으로 합쳐집니다. type과 다른 Interface만의 특성입니다.

interface User {
  name: string;
}

interface User {
  age: number;
}

// 두 선언이 합쳐짐
const user: User = {
  name: "철수",
  age: 30,
};

선언 병합은 외부 라이브러리의 타입을 확장할 때 유용합니다. 라이브러리 소스를 수정하지 않고도 타입을 추가할 수 있습니다.

인덱스 시그니처

프로퍼티의 이름을 미리 알 수 없을 때 사용합니다.

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

const config: StringMap = {
  host: "localhost",
  port: "3000",
  debug: "true",
};

함수 타입으로 사용

Interface로 함수의 형태도 정의할 수 있습니다.

interface Formatter {
  (value: string, locale: string): string;
}

const formatDate: Formatter = (value, locale) => {
  return new Date(value).toLocaleDateString(locale);
};

Interface는 코드 곳곳에서 같은 구조를 강제하는 계약 역할을 합니다. 함수 매개변수, 반환값, 클래스 구현 등 어디서나 Interface를 타입으로 사용하면, 구조가 어긋날 때 컴파일러가 즉시 알려줍니다.

← 이전 글Type Alias — 타입에 이름 붙이기
다음 글 →유니온과 교차 타입 — 타입을 조합하는 두 가지 방법