인터페이스는 상호 간에 정의한 약속 혹은 규칙을 의미합니다. 타입스크립트에서의 인터페이스는 보통 다음과 같은 범주에 대해 약속을 정의할 수 있습니다.
인터페이스는 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에서의 자동완성 지원이 가능해 집니다.
자바와 같은 전통적인 OOP에서의 interface에서는 위와 같이 인터페이스를 정의해주었지만 typescript에서는 다음과 같이 정의해 줄 수도 있습니다.
interface Cell {
row: number;
col: number;
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를 앞에 붙여서 속성을 정의하면 처음 생성할 때 값을 할당하고 후에 값을 변경할 수 없습니다.
interface CraftBeer {
readonly brand: string;
}
배열을 선언할 때 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 login {
(username: string, password: string): boolean;
}
다음과 같이 사용해 줄 수 있겠죠?
let loginUser: login;
loginUser = function(id: string, pw: string) {
console.log('로그인 했습니다');
return true;
}
자바처럼 타입스크립트에서도 클래스가 일정 조건을 만족하도록 타입 규칙을 정할 수 있습니다.
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;
}
추가부분은 인터페이스 | 타입스크립트핸드북 을 참고하였습니다.