📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄

[TypeScript] 객체의 타입을 정의할 때 쓰면 좋은 interface

인터페이스(interface)란?

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

interface란 상호 간에 정의된 규칙이라는 뜻으로 타입스크립트에서는 객체의 타입을 지정할 때 많이 사용한다.

기존에 배운 type 선언처럼 interface를 선언할 때도 같은 방식으로 선언해준다. 일반적으로 interface는 객체의 타입을 정할 때 사용되며, 확장 기능이나 선업 병합과 같은 기능들로 인해서 객체를 정의할 때 interface 선언을 사용하는 것이 보편적이다. 또한, 선언을 할 때 '='를 사용하지 않고 바로 중괄호를 열어서 사용한다는 점도 type과의 차이점이라고 할 수 있다.

 

사용 방법

interface Person {
    name: string;
    age?: number;
    sayHi(): void;
    sayHi(a: number, b: string): void;
}

const person: Person = {
    name: 'shawn',
    sayHi: function () {
        console.log('Hi');
    }
}

person.name;
person.sayHi();

interface를 선언하는 방법은 간단하다. 프로퍼티의 값마다 타입을 선언해주면 되고, 옵셔널 체이닝으로 선택적 프로퍼티를 만들어 줄 수도 있으며 readonly 속성을 줄 수도 있다.

 

인터페이스 확장 (extends)

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

interface Cat extends Animal {
    color: string;
    // 확장으로 인해 Animal 타입의 name, age도 포함됨
}

interface Test extends A, B {} // 여러 개의 타입을 확장할 수도 있음

인터페이스의 꽃은 아무래도 확장이 아닐까 싶다. 또한 확장을 사용한다는 점에서 타입 별칭(type)과 가장 큰 차이가 있지 않나 싶다. 기존에 선언했던 interface가 있다면 그대로 가져와서 추가할 프로퍼티만 추가하면 되니까 재사용성 측면에서도 좋고 사용하기도 훨씬 편하다. (type에서는 type끼리 확장/상속이 안되므로 union이나 intersection 타입을 써야 한다.)

확장을 하면 확장으로 불러온 인터페이스의 프로퍼티 타입들이 import 된다고 생각하면 된다. 또한, 여러 개의 타입을 확장 할 수도 있다.

interface Animal {
    name: string;
    color: string;
}

interface Monkey extends Animal {
    color: 'brown'; // 재정의 가능. 대신 원본 타입의 서브 타입만 가능
}

확장된 인터페이스에서 기존에 정의된 프로퍼티의 타입을 재정의 해줄 수도 있다. 위 코드에서 Animal의 color는 string 타입이었지만, 확장된 Monkey에서 color를 문자 리터럴 타입으로 다시 재정의해주었다. (무조건 서브 타입만 올 수 있다.)

리터럴 타입은 원시 타입의 서브 타입이므로 가능하며, 만약 슈퍼 타입이거나 동일한 기본 타입이었다면 재정의가 되지 않는다.

interface Person {
    name: string;
}

interface Person {
    age: number;
}

interface Person {
    name: number; // Error! 기존 선언된 타입은 건드릴 수 없음
}

type과 달리 interface는 재정의가 가능하다. 또한, 재정의된 interface는 원본과 공유되기 때문에 자연스럽게 하나의 interface로 합쳐진다. 이것을 '선언 병합'이라고 한다.

 

Person이라는 인터페이스가 이미 선언되어 있고, 거기에 age 프로퍼티의 타입을 주는 것을 깜빡했다고 하자. 그럴 때는 간단하게 밑에 다시 같은 이름으로 재정의해주면 된다. Person에 age 프로퍼티 타입만 따로 추가해주면, 원본과 공유되기 때문에 결과적으로 Person 인터페이스 안에는 name과 age가 있게 된다.

 

한 가지 주의할 점이 있다면 재정의를 할 때 이미 선언되어 있는 프로퍼티의 타입은 건드릴 수 없다는 점이다. 명시적으로 인터페이스를 재정의하기 위해 원본 인터페이스의 프로퍼티를 다시 써야하는 상황이라면, 기존 인터페이스에 있는 타입 그대로 써야하며 서브 타입 조차도 올 수 없다.

 

1. interface객체일 때 사용한다.
2. interface A extends B : 이미 선언된 B 타입을 A 타입에서 불러온다. (인터페이스 확장)
3. interface A extends B에서 A는 B의 프로퍼티를 재정의할 수 있다. 단, 서브 타입만!
4. interface 자체를 재정의할 수도 있다. 같은 인터페이스 이름으로 한 번 더 써주면 된다.