TypeScript에서 인터페이스와 타입의 차이, 장단점, 탄생배경

park.js·2024년 9월 11일
4

FrontEnd Develop log

목록 보기
29/37

TypeScript에서 인터페이스(interface)타입(type)은 모두 객체의 형태와 구조를 정의하는 데 사용됨.

1. 인터페이스와 타입의 탄생 배경

인터페이스는 TypeScript가 처음 설계될 때부터 있던 기능임. Java와 같은 객체 지향 언어의 영향을 받아 클래스와 연동되는 구조적인 정의가 필요했기 때문에 인터페이스가 도입되었음.

타입은 이후 TypeScript에 추가된 기능으로, 더 유연하고 함수형 프로그래밍 스타일을 지원하는 방식으로 설계되었음. 다양한 데이터 구조를 유연하게 정의할 수 있는 도구로 발전했음.

2. 인터페이스와 타입의 핵심 차이점

2.1 선언적 확장

인터페이스는 선언적 확장이 가능
즉, 동일한 이름의 인터페이스를 여러 번 선언할 수 있으며, TypeScript는 이를 하나의 인터페이스로 병합함. 이는 코드 확장성과 유지보수 측면에서 큰 장점을 가짐.
하지만 이미 선언된 interface를 모르고 중복 사용할 경우 오류가 나는 경우가 있어 이는 단점이 될 수도 있음.

interface User {
  name: string;
}

interface User {
  age: number;
}

const user: User = {
  name: "박지성",
  age: 25, // 병합된 인터페이스를 통해 이름과 나이 모두 사용 가능
};

타입은 확장될 수 없고, 한 번 선언된 타입은 재선언할 수 없음.

type User = {
  name: string;
};

// Error: Duplicate identifier 'User'. 발생
type User = {
  age: number;
};

2.2 유니온(Union)과 인터섹션(Intersection)

타입은 유니온과 인터섹션 타입을 지원함.
즉, 여러 타입을 조합하거나(유니온), 합칠 수(인터섹션) 있음.

type Pet = { name: string };
type Dog = Pet & { breed: string }; // 인터섹션

const dog: Dog = { name: "Buddy", breed: "Labrador" };

유니온 타입도 가능

type StringOrNumber = string | number;

반면, 인터페이스는 유니온 타입을 지원하지 않음.

2.3 클래스와의 호환성

인터페이스는 주로 클래스와 연동해서 사용됨.
TypeScript에서 인터페이스는 클래스의 형태를 정의하고 클래스가 특정한 구조를 따르게 강제할 수 있음.

interface Animal {
  name: string;
  speak(): void;
}

class Dog implements Animal {
  name = "Buddy";
  speak() {
    console.log("Woof!");
  }
}

타입은 클래스에 직접적으로 사용되기보다는 객체의 구조를 정의하거나 함수의 반환 타입 등을 정의하는 데 자주 사용됨.

3. 장단점

3.1 인터페이스의 장점

  • 확장성: 여러 번 선언이 가능하고 병합되므로 코드 확장이 용이함.
  • 클래스와의 자연스러운 연동: 클래스가 특정 구조를 따르게 할 때 유용함.

3.2 인터페이스의 단점

  • 유연성 부족: 유니온 타입이나 인터섹션 타입을 지원하지 않음.
  • 구조적 제한: 더 복잡한 구조나 동적 타입을 선언하는 데 제약이 있음.

3.3 타입의 장점

  • 유연성: 유니온과 인터섹션 타입 지원으로 복잡한 타입을 표현할 수 있음.
  • 복합 타입 지원: 객체, 유니온, 인터섹션 등 다양한 형태의 타입 선언이 가능.

3.4 타입의 단점

  • 확장성 부족: 한 번 선언된 타입은 재선언할 수 없으므로 확장성 면에서 인터페이스보다 제한적임.

4. 예시 코드

4.1 인터페이스 사용 예시

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

const user: User = {
  name: "박지성",
  age: 25,
};

4.2 타입 사용 예시

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

const user: User = {
  name: "박지성",
  age: 25,
};

4.3 유니온 타입 예시

type StringOrNumber = string | number;

let value: StringOrNumber;

value = "하잉";
value = 123;

4.4 인터섹션 타입 예시

type Person = { name: string };
type Employee = { employeeId: number };

type Staff = Person & Employee;

const staff: Staff = {
  name: "박지성",
  employeeId: 217,
};

5. 공식 문서 권장 사항

TypeScript 공식 문서에서는 인터페이스타입을 사용하는 상황에 대해 다음과 같은 가이드를 제시함:

5.1 인터페이스를 사용할 때

  • 객체 지향적인 구조가 필요한 경우: 클래스와 연동하여 사용할 때는 인터페이스를 사용하는 것이 좋음.
  • 확장과 병합이 필요할 때: 여러 선언을 병합하여 하나의 인터페이스로 만들 수 있으므로, 확장이 예상되는 경우 인터페이스를 권장함.
interface Animal {
  name: string;
}

interface Animal {
  age: number;
}

const animal: Animal = { name: "강아지", age: 3 };

5.2 타입을 사용할 때

  • 유연한 타입 조합이 필요한 경우: 유니온 타입이나 인터섹션 타입을 사용할 때는 타입을 사용하는 것이 적합함.
  • 동적이고 복합적인 타입을 다룰 때: 함수형 프로그래밍 스타일을 따르거나, 다양한 데이터 구조를 유연하게 정의할 때는 타입을 사용하는 것이 더 적합함.
type ID = string | number;

6. 결론

인터페이스타입은 TypeScript에서 각각의 강점과 용도를 가지고 있음. 객체지향적인 구조를 정의하고 확장이 필요한 경우에는 인터페이스가 적합하며, 유연하고 복잡한 데이터 구조를 정의할 때는 타입을 사용하는 것이 좋음.

권장사항 요약:

  • 클래스와 연동, 확장성: 인터페이스 사용
  • 유니온, 인터섹션, 복합 타입: 타입 사용

7. 보충내용

extends&의 차이점

  • 위 내용에서 타입에서 인터섹션을 사용하여 속성 확장이 가능하다고 언급하였음. interface도 객체지향적으로 extends 상속이 가능함.
    extends: 상속을 의미. 타입의 인터섹션과 기능은 같지만 개념이 다름.
    • extends는 상속 개념으로, 인터페이스 확장을 위해 사용됨.
    • &는 여러 타입을 결합하는 방식으로, 모든 속성을 합쳐 새로운 타입을 만듬.
  • extends 예시:

    interface Person {
      name: string;
      age: number;
    }
    
    interface Employee extends Person {
      salary: number;
    }

Omit 사용 방법

Omit은 타입이나 인터페이스에서 특정 속성을 제외하고 싶을 때 사용됨.

  • 타입에서 Omit 사용:

    type Person = { name: string; age: number; address: string; }
    type PersonWithoutAddress = Omit<Person, "address">;
  • 인터페이스에서 Omit 사용:

    interface Person {
      name: string;
      age: number;
      address: string;
    }
    
    interface PersonWithoutAddress extends Omit<Person, "address"> {}

요약

  • extends: 상속 개념으로, 인터페이스를 확장할 때 사용.
  • &: 여러 타입을 합쳐 새로운 타입을 만들 때 사용.
  • Omit: 특정 속성을 제외한 타입이나 인터페이스를 정의할 때 사용.
profile
참 되게 살자

0개의 댓글