TS Types와 Interfaces를 사용하는 방법 및 시기

TS Types와 Interfaces를 사용하는 방법 및 시기
TILPosted On Jul 2, 20246 min read

TypeScript를 처음 접했을 때 인터페이스와 타입이 서로 교환 가능해 보일 수 있습니다, 특히 객체 모양을 설명할 때입니다. 실제로 TPerson 및 IPerson을 모두 가져오는 코드를 볼 수 있는데, 이는 둘 다 클래스 또는 객체 구조를 정의할 수 있다는 것을 시사합니다. 이 명백한 유사성은 각각을 사용해야 할 때에 대한 혼란을 야기할 수 있습니다.

그러나 중요한 차이가 존재합니다: 인터페이스는 객체 및 클래스를 설명하는 데 사용되지만, 타입은 어떤 유형의 데이터 구조든 표현할 수 있습니다. 이 기본적인 대조는 TypeScript 프로젝트에서 각각을 언제 사용해야 할지에 대한 기준을 마련합니다.

명백한 유사성

다음과 같이 보이는 동등한 정의를 고려해보세요:

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

type TPerson = {
  name: string,
  age: number,
};

const person1: IPerson = { name: "Alice", age: 30 };
const person2: TPerson = { name: "Bob", age: 25 };

IPerson과 TPerson은 둘 다 이름과 나이 속성을 가진 객체를 설명할 수 있지만, 그 기능은 여기서부터 다릅니다.

인터페이스: 클래스 제한을 위한 전문가

TypeScript의 인터페이스는 특정 목적에 맞게 설계되었습니다: 객체와 클래스의 형태를 설명하는 데 사용됩니다. 원시 값의 별칭을 만들거나, 결합 유형 또는 교차 유형을 생성하는 데 사용할 수 없습니다. 이 특화된 기능은 인터페이스를 객체지향 프로그래밍 시나리오에서 특히 강력하게 만듭니다.

TypeScript을 공부할 때 인터페이스와 타입의 차이를 이해하는 것이 중요합니다. 기억해야 할 주요 차이는 인터페이스는 객체와 클래스를 설명하는 데만 사용되지만, 타입은 어떤 종류의 데이터 구조든 나타낼 수 있다는 점입니다. 이 기본적인 대조는 TypeScript 프로젝트에서 각각을 언제 어떻게 사용해야 하는지를 결정합니다.

인터페이스의 주요 장점은 다음과 같습니다:

  • 객체 모양 정의: 인터페이스는 객체가 특정 구조를 준수하는지 확실하게 보장하는 방법을 제공합니다.
  • 확장성: 인터페이스를 확장할 수 있어 복잡한 객체 유형을 시간이 지남에 따라 발전시키는 데 이상적입니다.
  • 클래스 구현: implements 키워드를 이용하여 클래스를 제한하고 인터페이스 계약을 준수하도록 함으로써 코드의 견고성을 향상시킵니다.

간단한 예시를 살펴보겠습니다.

interface IAnimal {
  name: string;
  age: number;
  speak(): void;
}

class Dog implements IAnimal {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  speak() {
    console.log("Woof!");
  }
}

그리고 여기에 extends 키워드를 잘 활용한 예제가 있어요.

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

interface IDog extends IAnimal {
  breed: string;
  wagTail(): void;
}

class Dog implements IDog {
  name: string;
  breed: string;

  constructor(name: string, breed: string) {
    this.name = name;
    this.breed = breed;
  }

  speak() {
    console.log("Woof!");
  }

  wagTail() {
    console.log(`${this.name}가 꼬리를 흔들고 있어요.`);
  }
}

const myDog = new Dog("Buddy", "Labrador");
myDog.speak();
myDog.wagTail();

주의하셔야 할 점은 아래의 문법이 객체를 제한하는 경우에서는 클래스가 아닌 객체를 제한하는 경우에만 맞는 구문이에요:

인터페이스 IPerson {
  이름: 문자열;
  나이: 숫자;
}

상수 person1: IPerson = { 이름: "Alice", 나이: 30 };

타입: 다재다능한 파워하우스

인터페이스는 객체 모양에만 제한되지만, 타입은 더 다양한 가능성을 제공합니다:

  • 다재다능성: 타입은 객체뿐만 아니라 기본 유형, 유니온, 교차, 튜플 등을 대표할 수 있습니다.
  • 복잡한 타입 작성: 유니언(|) 및 교차(&) 연산자로 타입을 정교하게 정의할 수 있습니다.
  • 별칭: 타입 별칭은 복잡한 타입에서 코드 가독성을 높일 수 있습니다.

다음은 예제 입니다:

type TName = string;
type TAge = number;

type TPerson = {
  name: TName,
  age: TAge,
};

type TAnimal = {
  name: string,
  age: number,
  speak(): void,
};

type TDog = TAnimal & { breed: string };

const myDog: TDog = {
  name: "Buddy",
  age: 5,
  breed: "Golden Retriever",
  speak() {
    console.log("Woof!");
  },
};

인터페이스와 유형 사이 선택하기

각각의 한계와 강점을 이해하고, 다음 권장 사항을 고려해보세요:

  • Interfaces를 사용하는 경우:

    • 오브젝트나 클래스와 작업할 때
    • 오브젝트가 지켜야 하는 계약을 정의할 때
    • 오브젝트 정의를 확장하거나 병합해야 할 때
  • Types를 사용하는 경우:

    • 오브젝트를 포함한 모든 종류의 타입 정의를 생성할 때
    • 유니언, 교차 또는 기본형과 작업할 때
    • 타입 생성에서 최대 유연성이 필요할 때

결론

TypeScript에서의 인터페이스와 타입의 차이는 분명합니다: 인터페이스는 오브젝트 형태를 설명하는 데 특화되어 있고, 타입은 모든 종류의 타입 정의에 대해 더 큰 유연성을 제공합니다. 이 기본적인 차이를 이해하면 TypeScript 프로젝트에서 보다 정보를 얻고 더 나은 결정을 내릴 수 있습니다.

인터페이스는 클래스 기반 시나리오에서 뛰어나며, 오브젝트 구조의 일관성을 보장해야 하는 경우에 유용합니다. 타입은 그들의 다양성으로 인해 복잡한 정의와 다양한 데이터 구조에 대한 가독성 향상에 필요한 도구입니다.

마지막으로, 클래스와 타입을 제한하는 데 인터페이스를 사용하고 그 외에는 거의 모든 것에 인터페이스를 사용해야 합니다. 이렇게 하면 더 표현력이 뛰어나고 유지보수하기 쉽고 견고한 TypeScript 코드를 작성할 수 있습니다. 기억하세요, 이 도구들을 사용하여 시간이 지나도 유지할 수 있는 명확하고 자기 설명적인 코드를 작성하는 것이 목표입니다.