6. 인터페이스 (1)

2021. 11. 7. 20:25재주껏 하는 Front-End/타입스크립트 (준비중)

반응형

이번 글에서는 타입스크립트의 인터페이스에 대해 알아보자.

 

인터페이스란, 두 개 이상의 시스템 사이에서 상호 작용을 할 수 있도록 하는 조건 또는 규약을 말한다. 즉, 타입스크립트의 변수, 함수, 클래스 등이 지켜야 할 최소 구조를 정의하는 것이다. 따라서 인터페이스를 사용한다는 것은 새로운 타입을 만드는 것과 같다.

 

타입스크립트에서 가장 중요한 것은 타입을 생성하고 적용하는 것이기 때문에 인터페이스는 타입스크립트에서 높은 비중을 차지한다. 아마 많은 타입스크립트 코드에서 인터페이스를 아주 쉽게 찾아볼 수 있을 것이다. 타입스크립트는 아래와 같은 경우에 정의할 수 있다.

 

  • 객체 또는 배열
  • 함수
  • 클래스

 

1. 인터페이스의 선언

 

인터페이스는 아래와 같은 방법으로 선언한다. 위에서 알아본 것과 같이 변수에 할당되는 객체나 배열의 타입을 상세하게 정의할 수 있으며 심지어 함수의 파라미터나 리턴 값까지도 정의할 수 있는 것을 알 수 있다.

 

// 1. 객체 인터페이스
interface ObjectInterface {
  멤버1: 멤버1에 저장될 타입;
  멤버2: 멤버2에 저장될 타입;
  멤버3: 멤버3에 저장될 타입;
}

// 2. 배열 인터페이스
interface ArrayInterface {
  [index: number]: 배열에 저장될 타입
}

// 3. 함수 인터페이스
interface FunctionInterface {
  (파라미터1: 파라미터1 타입, 파라미터2: 파라미터2 타입, ...): 함수 리턴 타입
}

 

2. 인터페이스 사용 예제

 

2.1 객체 인터페이스

 

가장 먼저 객체 인터페이스를 사용해보자. 아래의 코드는 ReviewDev 인터페이스로 변수 revDev의 타입을 지정하는 예제 코드이다. 인터페이스의 멤버에는 Number 타입의 age와 String 타입의 name이 있다. 컴파일을 수행하면 문제없이 완료되는 것을 확인할 수 있다.

 

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

let revDev: ReviewDev = {
    age: 32,
    name: '리뷰하는 개발자'
}

console.log('객체 인터페이스 > ', revDev)

 

만약, 위의 코드에서 age를 빼면 어떨까? 바로 확인해보자.

 

 

위와 같이 필수 멤버인 age가 없다고 바로 에러 메시지가 출력된다. 만약, age의 값을 문자열로 바꾸면 어떻게 될까? 아래와 같이 에러가 발생한다.

 

자바스크립트의 객체는 제약 사양이 없어서 의도치 않은 멤버가 추가되거나 값이 변경되어 문제가 발생하는 경우가 많은데, 타입스크립트에서는 인터페이스를 사용하여 이러한 문제가 나타나는 것을 사전에 방지할 수 있다.

 

 

그렇다면 멤버의 유무가 확실치 않을때는 어떻게 해야 할까? 위의 코드를 아래와 같이 변경해보자. 컴파일 실행 결과 age가 빠졌음에도 에러가 발생하지 않고 정상적으로 종료된다. 아래와 같이 멤버가 필수가 아닌 경우 이름 뒤에 "?" 를 붙여 대상 멤버가 없을 수도 있다는 것을 컴파일에 알려줄 수 있다. 이것을 옵션 속성이라고 한다.

 

interface ReviewDev {
    age?: number;
    name: string;
}

let revDev: ReviewDev = {
    name: '리뷰하는 개발자'
}

console.log('객체 인터페이스 > ', revDev)

 

2.2 배열 인터페이스

 

이번에는 배열의 인터페이스를 살펴보자. 배열의 인덱스 타입과 인덱스를 사용하여 리턴되는 데이터의 타입을 인터페이스에 정의한다. 컴파일을 실행하면 오류 없이 동작하는 것을 확인할 수 있다.

 

interface CarList {
    [index: number]: string;
}

let carList: CarList = ['K5', 'SM6', 'SONATA', 'MALIBU']

 

2.3 딕셔너리 패턴

 

만약, 위에서 살펴본 배열 인터페이스의 인덱스의 타입을 변경하면 어떻게 될까? 아래와 같이 인덱스 타입을 문자열로 변경해보자.

 

interface CarList {
    [index: string]: string;
}

let carList: CarList = ['K5', 'SM6', 'SONATA', 'MALIBU']

 

실행 결과 아래와 같이 에러가 발생한다. 배열은 인덱스의 타입이 Number로 고정되어 있기 때문에 사실상 다른 타입으로 변경할 수 없다.

 

 

그렇다면 위의 코드가 동작되게 하려면 어떻게 해야 될까? 인덱스의 타입이 문자열인 타입으로 변경해주면 된다. 위의 구조를 객체로 변경해보자. 컴파일을 실행하면 에러 없이 정상 실행된다.

 

interface CarList {
    [index: string]: string;
}

let carList: CarList = {
    kia: 'K5',
    hyd: 'SONATA',
    sam: 'SM6',
    chv: 'MALIBU'
}

console.log('중형 세단 목록 > ', carList)

 

2.4 함수 인터페이스

 

이번에는 함수 인터페이스에 대해 알아보자. 아래의 코드를 보면 함수 인터페이스 GetSmartPhone 내부에 model과 price라는 두 개의 파라미터를 받고 리턴 값으로 SmartPhone이라는 객체 타입을 리턴하도록 정의하였다. 컴파일 결과 에러 없이 정상적으로 실행된다.

 

interface SmartPhone {
    model: string;
    price: number;
}

interface GetSmartPhone {
    (model: string, price: number): SmartPhone;
}

let getSmartPhoneInfo: GetSmartPhone;

getSmartPhoneInfo = function (model: string, price: number): SmartPhone {
    return {
        model,
        price
    }
}

console.log('스마트폰 정보 > ', getSmartPhoneInfo('Samsung Galuxy S21', 999000))

 

2.5 클래스 인터페이스

 

이번에는 클래스 인터페이스에 대해 알아보자. 인터페이스를 상속받는 클래스를 만드는 방법은 다른 객체 지향 언어에서 아주 많이 사용하는 방법이지만, 자바스크립트의 경우에는 ES6 전까지는 클래스라는 개념이 따로 없었기 때문에 간단히 살펴보고 넘어가도록 한다.

 

예제 코드는 아래와 같이 작성하였다. 클래스 DclassSedan을 확장하여 ChevySadan이라는 인터페이스를 정의하였다. 다음, Malibu라는 클래스에 implements 키워드를 이용하여 ChevySedan 인터페이스 구조로 구성되도록 지정하였다.

 

class DclassSedan {
    price: number;
    power: number;
}

interface ChevySedan extends DclassSedan {
    getCarInfo(): void;
}

class Malibu implements ChevySedan {
    power: number;
    price: number;
    
    constructor () {
        this.power = 156
        this.price = 2895
    }

    getCarInfo() {
        console.log('더 뉴 말리부 2022 > ', this.price, this.power)
    }
}

let newChar = new Malibu()
newChar.getCarInfo()

 

실행 결과는 아래와 같다.

 

 

2.6 복합 인터페이스

 

위에 클래스 예제에서 나왔듯이 인터페이스는 여러 타입을 조합할 수 있다. 위의 클래스 예제 코드를 단일 인터페이스로 변경해보자. ChevySedan 인터페이스 내부에 Number 타입 멤버 2개와 getCarInfo라는 함수 타입이 동시에 정의되어 있는 것을 볼 수 있다. 실행 결과는 위와 동일하다.

 

interface ChevySedan {
    price: number;
    power: number;
    getCarInfo(): void;
}

class Malibu implements ChevySedan {
    power: number;
    price: number;
    
    constructor () {
        this.power = 156
        this.price = 2895
    }

    getCarInfo() {
        console.log('더 뉴 말리부 2022 > ', this.price, this.power)
    }
}

let newChar = new Malibu()
newChar.getCarInfo()

 


 

지금까지 타입스크립트의 인터페이스 기본에 대해 알아보았다. 다음 글에서는 인터페이스의 확장과 타입 별칭과의 차이에 대해 알아보자.

반응형

'재주껏 하는 Front-End > 타입스크립트 (준비중)' 카테고리의 다른 글

8. 기타 타입 (1)  (0) 2021.11.09
7. 인터페이스 (2)  (0) 2021.11.07
5. 타입 추론 / 별칭  (0) 2021.11.05
4. 기본 타입  (0) 2021.10.31
3. JS DOC  (0) 2021.10.29