Front-End/TypeScript

타입스크립트[TypeScript] | 인터페이스 vs Type alias

jaeyeong 2023. 4. 26. 15:22

🔍 글을 시작하기 전에

 

해당 글은 타입스크립트 프로그래밍 책과 유데미 타입스크립트 강의를 공부하여 정리한 글입니다.

수정해야 할 부분이 있다면 언제든지 알려주세요!

 

인터페이스

인터페이스는 객체의 구조(형태)를 설명한다.
타입을 작성하고 값을 할당하려고 하면 인터페이스는 이니셜라이져를 사용할 수 없다는 에러메시지가 뜬다.
이를 통해 인터페이스는 구체적인 값이 있는 구조가 아니라, 객체의 구조를 정의하는 것이라고 할 수 있다.

 

타입 별칭 vs 인터페이스

1) 기본 구조

// 타입 별칭
type Sushi = {
    calories: number
    salty: boolean
    tasty: boolean
}

// 인터페이스
interface Sushi {
    calories: number
    salty: boolean
    tasty: boolean
}

 

2) 인터섹션 타입

인터섹션 타입은 다른 타입을 결합하는 것이다.

 

- 타입 별칭

type Admin = {
  name: string;
  privileges: string[];
};

type Employee = {
  name: string;
  startDate: Date;
};

type ElevatedEmployee = Admin & Employee;

const e1: ElevatedEmployee = {
  name: 'Max',
  privileges: ['create-server'],
  startDate: new Date(),
};

 

- 인터페이스

// 1번
interface Admin {
  name: string;
  privileges: string[];
};

interface Employee {
  name: string;
  startDate: Date;
};

type ElevatedEmployee = Admin & Employee;

const e1: ElevatedEmployee = {
  name: 'Max',
  privileges: ['create-server'],
  startDate: new Date(),
};

// 2번
interface Admin {
  name: string;
  privileges: string[];
}

interface Employee {
  name: string;
  startDate: Date;
}

interface ElevatedEmployee extends Admin, Employee {}

const e1: ElevatedEmployee = {
  name: 'Max',
  privileges: ['create-server'],
  startDate: new Date(),
};

 

3) 중복되는 프로퍼티를 공통 정보로 정의한 구조

// 타입 별칭
type Food = {
    calories: number
    tasty: boolean
}
  
type Cake = Food & {
    sweet: boolean
}

// 인터페이스
interface Food {
    calories: number
    tasty: boolean
}

interface Cake extends Food {
    sweet: boolean
}

 

4) 함수 타입 정의

// 타입 별칭
type AddFn = (a: number, b:number) => number
const add: AddFn = (x: number, y: number) => x + y;

console.log(add(1,3)); // 4

// 인터페이스
interface AddFn {
    (a: number, b:number): number
}

const add: AddFn = (x: number, y: number) => x + y;

console.log(add(1,3)); // 4

 

5) 차이점

1. 오른편에 올 수 있는 형태

타입 별칭의 오른쪽엔 타입 표현식을 포함한 모든 타입이 올 수 있으나

type A = number

type B = A | string

인터페이스의 오른쪽엔 반드시 형태가 나와야 한다.

 

2. 상위 타입의 상속

인터페이스는 상속받는 인터페이스 타입에 상위 인터페이스를 할당할 수 있는지 확인하며

타입 별칭은 확장하는 타입을 최대한 조합하여, 상위 타입을 오버로드 하기도 한다.

 

A의 bad함수의 x는 number, B의 bad함수의 x는 string일 경우
number 타입은 string 타입에 할당할 수 없다며 B는 A를 올바르게 상속받지 않는다는 오류를 발생시킨다.

객체 타입의 상속을 표현할 땐 인터페이스를 사용하여 에러를 쉽게 감지할 수 있다.

interface A {
    good(x: number): string
    bad(x: number): string
}

interface B extends A {
    good(x:number | string): string
    bad(x: string): string
}

 

위 인터페이스 정의를 타입 별칭으로 바꾸면 다음과 같이 바꿀 수 있는데,

A의 bad 함수 타입 정의를 오버로드한 시그니처가 만들어지게 되어 오류가 발생하지 않는다.

type A = {
    good(x: number): string
    bad(x: number): string
}

type B = A & {
    good(x:number | string): string
    bad(x: string): string
}

 

3. 선언 합침

이름과 범위가 같은 인터페이스가 여러 개 있다면 자동으로 합쳐지며

타입 별칭은 같은 조건일 때 컴파일 에러가 발생한다.

 

선언 합침

name 프로퍼티를 가진 User 인터페이스를 정의하고,

age 프로퍼티를 가진 User 인터페이스를 정의하면 다음과 같다.

interface User {
    name: string
}

interface User {
    age: number
}

 

User 인터페이스의 타입으로 지정한 변수 a를 살펴보면,

let a: User = {
    name: '재영', // Error: age 프로퍼티가 없음
}

let a: User = {
    name: '재영',
    age: 100
}

 

위와 같이 name, age 프로퍼티를 모두 작성해야 하는 것을 확인할 수 있었다.

 

타입 별칭을 사용하여 이름을 같게 정의한다면 에러가 발생하는 것을 확인했다.

type Person = {
    name: string // Error: 중복 식별자 Person
}

type Person = {
    age: number // Error: 중복 식별자 Person
}

 

implements

implements를 사용하여 특정 인터페이스를 타입으로 지정한 클래스를 선언할 수 있다.

이때 인터페이스에서 선언한 모든 메서드를 구현해야 한다.

(추가 속성이 필요하다면 메서드나 프로퍼티를 오버로드하여 구현할 수 있다.)

 

만약 프로퍼티를 정의한다면, private, protected, public, static 키워드는 사용할 수 없고

readonly 키워드는 사용할 수 있다.

 

찾아보니 private, protected, public, static 키워드는 클래스 구현과 관련되어 있는데

인터페이스는 다양한 클래스에서 공통적으로 사용되는 메서드와 속성의 형태를 정의하는 것이 목적이지

클래스의 구현과는 상관이 없기 때문이라고 한다.

interface Animal {
    readonly name: string
    eat(food: string): void
    sleep(hours: number): void
}

class Cat implements Animal {
    name = '은동'
    eat(food: string) {
        console.log(food, '를 먹었다냥')
    }
    sleep(hours: number) {
        console.log(hours, '시간 잔다냥')
    }
}