0%

타입스크립트 인터페이스

1_vK1lTdXqCjv7ob_j0TePLQ

1. 소개

인터페이스는 일반적으로 타입체크를 위해 사용되며 변수,함수,클래스에 사용할 수 있다.여러가지 타입을 갖는 프로터피로 이루어진 새로운 타입을 정의하는 것과 유사하다. 인터페이스는 선언된 프로퍼티 또는 메소드의 구현을 강제하여 일관성을 유지할 수 있도록 하는것이다. ES6 인터페이스는 지원을 지원하지 않지만 TypeScript는 인터페이스를 지원한다.

인터페이스는 프로퍼티와 메소드를 가질수 있다는 점에서 클래스와 유사하나 직접 인스턴스를 생성 할 수없고 모든 메소드는 추상 메소드이다. 단 추상 클래스의 추상 메소드와 달리 abstarct 키워드를 사용하지 않는다.

2. 변수와 인터페이스

인터페이스는 변수의 타입으로 사용할 수 있다. 이때 인터페이스를 타입로 선언한 변수는 해당 인터페이스를 준수 하여야한다. 이서은 새로운 타입을 정의하는것과 유사하다.

1
2
3
4
5
6
7
8
9
10
11
12
//인터페이스의 정의 
interface Todo{
id:number;
content:string;
completed:boolean;
}

//변수의 todo 타입으로 Todo 인터페이스를 선언하였다.
let todo = Todo;

//변수 todo는 Todo 인터페이스를 준수해야한다.
todo = {id:1,content:'typescript',completed:false};

인터페이스를 사용하여 함수 파라미터의 타입을 선언할 수있다. 이때 해당 함수에는 파리미터의 타입으로 지정한 인터페이스를 준수하는 인수를 전달하여 야한다. 함수의 객체를 전달할 때 복잡한 매개변수 체크가 필요없어 매우 유용하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//인터페이스의 정의 
interface Todo {
id:number;
content:string;
completed:boolean;
};
let todos = Todo:[] =[];

//파라미터 todo의 타입으로 Todo 인터페이스를 선언하였다.
function addTodo(todo:Todo){
todos = [...todos,todo];
}

//파라니터 todo는 Todo 인터페이스를 준수해야한다.
const newTodo = {id:1,content:'typescript',completed:false};
addTodo(newTodo);
console.log(todos);
//// [ { id: 1, content: 'typescript', completed: false } ]

3. 함수와 인터페이스

인터페이스는 함수의 타입으로 사용할수있다. 이때 함수의 인터페이스에는 타입이 선언된 파라미터 리스트와 리턴 타입으로 정의한다. 함수 인터페이스를 구현하는 함수는 인터페이스를 준수해야한다.

1
2
3
4
5
6
7
8
9
//함수 인터페이스의 정의 
interface SpuareFunc {
(num:number):number;
}
//함수 인터페이스를 구현하는 함수는 인터페이스를 준수해야한다.
const squareFunc :SquareFunc = function (num:number){
return num * num;
}
console.log(squareFunc(10)) // 100;

4. 클래스와 인터페이스

클래스이 선언문의 implements 뒤에 인터페이스를 선언하면 해당 클래스는 인터페이스를 반드시 구현해야한다. 이는 인터페이스를 구현하는 클래스의 일관성을 유지할 수있는 장점을 갖는다.인터페이스는 프로퍼티와 메소드를 가질수 있다는 점에서 클래스와 유사하나 직접 인스턴스를 생성 할 수없다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//인터페이스의 정의
interface ITodo{
id:number;
content:string;
compelted:boolean;
};

//Todo 클래스의 ITodo 인터페이스를 구현해야한다.
class Todo implements ITodo{
constructor(
public id:number,
public content:string,
public completed:boolean
){}
}
const todo = new Todo(1,'Typescript',false);
console.log(todo);

인터페이스는 프로퍼티 뿐만이 아니라 메소드도 포함 할 수있다. 단 모든 메소드는 추상 메소드이어야한다. 인터페이스는 구현하는 클래스는 인터페이스에서 정의한 프로퍼티와 추상 메소드를 반드시 구현해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//인터페이스의 정의
interface IPerson{
name:string;
sayHello():void;
}
//인터페이스를 구현하는 클래스는 인터페이스에서 정의한 프로퍼티와 추상 메소드를 반드시 구현해야한다.
class Person implements IPerson{
//인터페이스에서 정의한 프로퍼티 구현
contructor(public name:string){}
//인터페이스에서 정의한 추상 메소드의 구현
sayHello(){
console.log(`Hello ${this.name}`);
}
}
function greeter(person:IPerson):void{
person.syaHello();
}
const me = new Person('kim');
greeter(me) // Hello kim;

5. 덕 타이핑 (Duck typing)

주의 해야 할것은 인터페이스를 구현하였다는 것 만이 카입 체크를 통과하는 유일한 방법은 아니다. 타입체크에서 중요한것은 값을 실제로 가지고 있는 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface IDuck{//1
quack():void;
}
class MallardDuck implements IDuck{//3
quack(){
console.log('Quack~');
}
}
class ReadheadDuck{//4
quack(){
console.log('q~~uak');
}
}
function makeNoise(duck:IDuck):void{//2
duck.quack();
}
makeNoise(new MallarDuck()); //Quack~
makeNoise(new MallarDuck()); //q~~uack //5
  1. 인터페이스 IDuck을 quck 메소드로 정의하였다.
  2. makeNoise 함수는 인터페이스 IDuck을 구현한 클래스의 인스턴스 duck을 인자로 전달 받는다.
  3. 클래스 MallardDuck은 인터페이스 IDuck을 구현하였다.
  4. 클래스 RedheadDuck은 인터페이스 IDuck을 구현하지않았지만 quak메소드를 갖는다.
  5. makeNoise 함수에 인터페이스에서 정의한 프로퍼티나 메소드를 가지고 있다면 그 인터페이스를 구현한 것으로 인정한다. 이것을 덕 타이핑 또는 구조적 타이핑이라고 한다.

인터페이스를 변수에 사용할 경우에도 덕 타이핑은 적용된다.

1
2
3
4
5
6
7
8
interface IPerson{
name:string;
}
function sayHello(person:IPerson):void{
console.log(`Hello ${person.name}`);
}
const me = {name:'kim',age:20};
sayHello(me) // Hello kim;

변수 me 는 인터페이스 IPerson과 일치 하지않는다. 하지만 IPerson의 name 프로퍼티를 가지고 있으면 인터페이스에 부합하는것으로 인정한다.

인터페이스는 개발 단계에서 도움을 주기위해 제공되는 기능으로 자바스크립트의 표준이 아니다. 따라서 위 예제의 TypeScript 파일을 자바스크립트의 파일로 트랜스파일링 하면 다음과 같이 삭제된다.

1
2
3
4
5
function sayHello(person){
console.log('Hello'+person.name);
}
var me = {name:'kim',age:20};
sayHello(me); //Hello kim;

6. 선택적 프로퍼티

인터페이스의 프로퍼티는 반드시 구현되어야한다. 하지만 인터페이스의 프로퍼티가 선택적으로 필요한 경우가 있을수 있다. 선택적으로 프로퍼티는 프로퍼티명 뒤에 ? 를 붙이며 생략하여도 에러가 발생하지않는다.

1
2
3
4
5
6
7
8
9
10
11
interface UserInfo{
username:string;
password:string;
age? :number;
address:string;
}
const userInfo:Userinfo = {
username:'kim@gmail.com',
passowrd:'12345';
}
console.log(userInfo);

선택적 프로퍼티를 사용하면 사용 가능한 프로퍼티를 파악 할 수있어서 코드를 이해하지 쉬워진다.

7. 인터페이스의 상속

인터페이스는 extends 키워드를 사용하여 인터페이스 또는 클래스의 상속을 받을 수있다.

1
2
3
4
5
6
7
8
9
10
11
12
interface Person{
name:string;
age?:number;
}
interface Student extends Person{
grade:number;
}
const student :Student = {
name:'kim',
age:20,
age:1
};

복수의 인터페이스를 상속받을 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Person{
name:string;
age? :number;
}
interface Developer {
skills:string[];
}
interface WebDeveloper extends Person,Developer{}

const webDeveloper :WebDeveloper = {
name:'kim',
age:20,
skills:['HTML','CSS','JAVASCRIPT'];
}

인터페이스는 인터페이스 뿐만이 아니라 클래스도 상속받을수 있다. 단 클래스의 모든 멤버(public,private,protected)가 상속되지만 구현까지 상속하지는 않는다.

1
2
3
4
5
6
7
8
9
10
11
class Person{
constructor(public name:string, public age:number){}
}
interface Developer extends Person{
skills:string[];
}
const developer : Developer = {
name:'kim',
age:20,
skills:['HTML','CSS','JavaScript'];
}