chap.3 Interface

유원근·2020년 12월 22일
0
post-thumbnail
post-custom-banner

인터페이스란 무엇일까요?

인터페이스는 상호 간에 정의한 약속 혹은 규칙을 의미합니다. 타입스크립트에서의 인터페이스는 보통 다음과 같은 범주에 대해 약속을 정의할 수 있습니다.

  • 객체의 스펙(속성과 속성의 타입)
  • 함수의 파라미터
  • 함수의 스펙(파라미터, 반환 타입 등)
  • 배열과 객체를 접근하는 방식
  • 클래스

사용법

인터페이스는 interface라는 키워드를 통해 정의할수 있어요.
TV라는 인터페이스를 만들어 볼것인데 인터페이스는 하나의 타입을 정의할 수 있어요!
tv는 겨는기능과 끄는 기능이 있죠?
그걸 인터페이스로 표현하면 다음과 같이 표현할 수 있습니다.

interface TV {
  turnOn();
  turnOff();
}

그리고 만약 새로운 myTV을 만든다고 가정해봅니다.
그 TV도 켜고 끄는 기능이 있기 때문에 위 TV의 인터페이스를 그대로 가져가게 되겠죠

이렇게 myTv의 타입이 TV라고 지정을 해주면 자동완성이 완벽하게!! 지원되는 것을 확인할 수 있어요.

이제 다시한번, interface쪽을 보면 아래와 같이 빨간줄이 쳐져있는것을 확인할 수 있습니다.

그 이유는 turnOn() , turnOff()의 기본 반환타입이 지정되어 있지 않기 때문입니다.

위와같이 인터페이스에 정의된 속성을 사용하지 않는것에는 문제가 발생하지만, 반대로 객체에 속성을 더 추가하는 것은 문제가 되지 않습니다.
즉, 속성갯수가 많아져도 상관은 없으며 속성의 순서를 지키지 않아도 상관없습니다.

반환값 설정

인터페이스에서 지정한 메서드의 반환값은 다음과 같이 지정해 줄 수 있습니다.

interface TV {
  turnOn(): boolean;
  turnOff(): void;  //반환값이 없다면 void입니다. 
}

이렇게 되면 위와같이 turnOn의 반환값이 boolean값으로 지정되어 있기 때문에 myTv에서도 반환값을 boolean값으로 설정해주어야만 합니다.

const myTv: TV = {
  turnOn() {
    return true;
  },
  turnOff() {},
};

Interface에서는 구현체는 따로 있고, 어떠한 행위와 같은것을 한다고 묘사(정의)만 해놓습니다. 마치 자바의 interface와 비슷하죠?

인터페이스를 왜 쓰지?

인터페이스의 장점은 다음과 같을경우 사용될 수 있습니다.
만약 티비를 켜는 함수 tryTurnOn을 만든다고 가정해보고, 그 안에 매게변수로 해당 tv를 넣어줄 것입니다.

function tryTurnOn(tv:TV){

}

하지만, 아직 함수를 사용하기 이전이기 떄문에 무슨 tv가 들어올지 알 수가 없죠?
다음과 같이 매게변수로 TV라는 인터페이스의 tv가 올 것이다. 라고 해준다면 다음과 같이 IDE에서의 자동완성 지원이 가능해 집니다.

타입스크립트의 interface

자바와 같은 전통적인 OOP에서의 interface에서는 위와 같이 인터페이스를 정의해주었지만 typescript에서는 다음과 같이 정의해 줄 수도 있습니다.

가로세로행,열과 말을 가지고 있는 보드판이 있습니다.
interface Cell {
  row: number;
  col: number;
  piece: Piece;
}
말은 Piece라는 인터페이스타입인데 그 Piece인터페이스에는 말이 움직이는 기능에 대한 정의가 있습니다.
interface Cell {
  row: number;
  col: number;
  piece: Piece;
}

interface Piece {
  move(from: Cell, to: Cell): boolean;
}

이런식으로 하면 대충 어떤 기능들인지 알 수가 있겠죠?

위를 바탕으로 4x3형식의 보드판을 만들어 봅니다!

function createBoard() {
  const cells: Cell[] = [];
  for (let row = 0; row < 4; row++) {
    for (let col = 0; col < 3; col++) {
      cells.push({
        row: row,
        col: col,
			//보드판에는 말이 없을 수도 있습니다.
      });
    }
  }
	return cells;
}

보드판에 말이 없을수도 있는데 interface에서는 piece를 꼭 넣어달라고 빨간줄을 띄워주고 있어요.

있을수도 없을수도있는 옵션값인경우

이런 경우에는 다음과 같이 ?를 넣어 인터페이스를 수정할 수 있습니다.

interface Cell {
  row: number;
  col: number;
  piece?: Piece;
}

?를 붙이게 되면 해당 속성을 option화 할 수 있습니다.

readonly (읽기전용)

readonly를 앞에 붙여서 속성을 정의하면 처음 생성할 때 값을 할당하고 후에 값을 변경할 수 없습니다.

interface CraftBeer {
  readonly brand: string;
}

readonly배열

배열을 선언할 때 ReadonlyArray 타입을 사용하면 읽기 전용 배열을 생성할 수 있습니다.

let arr: ReadonlyArray<number> = [1,2,3];
arr.splice(0,1); // error
arr.push(4); // error
arr[0] = 100; // error
arr = [10, 20, 30]; // error

위처럼 배열을 ReadonlyArray로 선언하면 배열의 내용을 변경할 수 없습니다. 선언하는 시점에만 값을 정의할 수 있으니 주의해서 사용하세요.

Interface는 컴파일시 JS로 변환되면서 사라지기 때문에 interface를 많이 작성한다고 해서 코드가 길어지거나 하는 문제는 발생하지 않습니다.
견고한 코드를 위해 작성해주도록 합시다!

인터페이스를 활용한 회원가입 예시

interface SignUp {
  email: string;
  id: string;
  password: string;
}

function signUpRequest(data:SignUp){
    
}

이렇게 되면 SignUp시에 꼭 필요한 데이터를 기술해놓은뒤 회원가입 요청시에 전달받는 인자에 그 타입을 지정해서 넣어줄 수도 있겠죠?
아래와 같은 자동완성기능은 덤입니다!

+ 추가

함수에서의 Interface

인터페이스는 함수에서 매개변수의 타입과 반환값의 타입을 정의할때 사용할 수도 있습니다.

interface login {
  (username: string, password: string): boolean;
}

다음과 같이 사용해 줄 수 있겠죠?

let loginUser: login;
loginUser = function(id: string, pw: string) {
  console.log('로그인 했습니다');
  return true;
}

Class에서의 Interface

자바처럼 타입스크립트에서도 클래스가 일정 조건을 만족하도록 타입 규칙을 정할 수 있습니다.

interface CraftBeer {
  beerName: string;
  nameBeer(beer: string): void;
}

class myBeer implements CraftBeer {
  beerName: string = 'Baby Guinness';
  nameBeer(b: string) {
    this.beerName = b;
  }
  constructor() {}
}

인터페이스 확장

클래스를 사용할때 처럼 인터페이스도 확장을 제공하고 있습니다.

interface Person {
name: string;
}
interface Developer extends Person {
skill: string;
}
let frontEnd = {} as Developer;

이런경우에는 frontEnd는 name과 skill 속성을 모두 가지게 되겠죠?

하이브리드 타입

자바스크립트의 유연하고 동적인 타입 특성에 따라 인터페이스 역시 여러 가지 타입을 조합하여 만들 수 있습니다. 예를 들어, 다음과 같이 함수 타입이면서 객체 타입을 정의할 수 있는 인터페이스가 있습니다.

interface CraftBeer {
  (beer: string): string;
  brand: string;
  brew(): void;
}

function myBeer(): CraftBeer {
  let my = (function(beer: string) {}) as CraftBeer;
  my.brand = 'Beer Kitchen';
  my.brew = function() {};
  return my;
}

추가부분은 인터페이스 | 타입스크립트핸드북 을 참고하였습니다.

post-custom-banner

0개의 댓글