개발 기술/타입스크립트

타입스크립트, 인터페이스와 타입 별칭

by GicoMomg (Lux) 2021. 10. 14.

타입스크립트에서는 인터페이스, 타입 별칭을 사용해 별도의 타입을 만들 수 있다.
이렇게 생성한 타입을 가지고 우리는 구체적인 인자 선언을 할 수 있는데, 그렇다면 인터페이스와 타입 별칭 방식의 차이는 무엇일까? 한 번 알아보자


1. 인터페이스 방식

1) 인터페이스란?

  • 인터페이스란, 어떤 객체가 어떠한 속성이나 메소드를 가짐을 선언하는 걸 말한다.
  • 객체의 형상(객체의 속성과 그 타입은 무엇인지 등)을 정의할 수 있다.
  • 타입스크립트에서는 이 인터페이스 방식을 통해, 인자나 함수의 구체직인 타입 체크가 할 수 있다.

(1) 인터페이스 예시

  • 아래 예시는 Person이라는 인터페이스를 만든 것이다.
  • Personage, name 속성을 가지며, 각각 number, string 타입을 가진다.
interface Person {
  age: number;
  name: string;
}



2) 인터페이스의 활용

(1) 변수에서 활용한 경우

  • 앞서 생성한 인터페이스를 변수에서 사용할 땐 변수명: 인터페이스 방식으로 사용한다.
const lala: Person = {
  age: 12,
  name: 'lala',
}



(2) 함수에서 활용한 경우

  • 함수 인자에서 인터페이스를 활용할 때는 (인자: 인터페이스) 방식으로 사용하면 된다.
// 함수에 인터페이스 활용
function getPerson(person: Person):void {
  console.log(person)
}

  • 만약 전달하는 인자에 하나의 속성이라도 누락하면 에러를 발생시킨다.
const cap = {
  age: 12,
}
getPerson(cap);


  • 그러므로 인터페이스에서 선언한 모든 속성을 인자로 주어야한다.
const cap = {
  age: 12,
  name: 'lala',
}
getPerson(cap);



(3) 함수 구조에 인터페이스 활용한 경우

  • 어떤 함수의 구조를 정의할 때, 인터페이스를 활용할 수 있다.
  • 먼저 인터페이스를 이용해 함수의 인자와 리턴 타입을 선언한다.
interface sumFunc { 
  (a: number, b:number): number;  //(인자1, 인자2): 리턴타입
}

  • 그리고 함수명:인터페이스 형식으로 활용할 수 있다.
const sum:sumFunc =(a, b)=> {  //함수:인터페이스
  return a+b;
}

  • 리턴타입이 void(리턴값이 없는 경우)인 인터페이스는 아래와 같이 선언하고 사용할 수 있다.
// 인터페이스 선언
interface logFunc {
  (a: number): void;
}
// 사용
let log:logFunc =(a)=> {}



(4) 인덱싱에 활용한 경우

  • 배열은 인덱스를 통해 값에 접근한다.
const arr = ['a', 'b', 'c'];
arr[0]; //a

  • 배열은 인터페이스를 사용해 배열의 구조를 선언할 수 있다.
// 인터페이스 생성
interface stringArr {
  [index: number]: string;
}

  • 사용할 때는 배열변수: 인터페이스 방식으로 사용한다.
// 사용
const arr2:stringArr = ['a', 'b', 'c'];

만약 arr2의 0번째 인덱스 값에 number를 할당하면 어떻게 될까?

arr2[0] = 505;

결과는 타입 에러이다.



(5) 딕셔너리에 활용한 경우

  • 딕셔너리란, key - value 형태의 값을 저장할 수 있는 자료구조이며, 객체라고도 불린다.
  • 우리는 정규표현식(regex)을 값으로 가지는 딕셔너리 인터페이스를 아래와 같이 정의할 수 있다.
interface strRegexDict {
  [key: number]: RegExp;   // 키: 값
}

  • 이렇게 선언한 인터페이스는 obj변수에서 사용할 수 있다.
// 사용
let obj:strRegexDict = {
  1: /abc/,    //key: RegExp
  2: /a**/,
}

  • 이렇게 딕셔너리의 구조를 인터페이스로 선언하면, 딕셔너리를 사용할 때 데이터 타입을 추론해준다.
Object.keys(obj).map((v) => {
  console.log(v)
})


  • 또한 딕셔너리 키값으로 접근하여 타입에 맞지 않는 값을 할당하려고 하면 에러를 띄워준다.
obj[1] = 12;   //error




3) 인터페이스와 상속

  • 인터페이스에서 종복되는 선언을 상속을 통해 해결할 수 있다.
//인터페이스 1
interface Person {
  name: string;
  age: number;
}

// 인터페이스 2
interface Teacher {
  name: string;
  age: number;
  subject: string;
}

  • interface 인터페이스명 extends 상속받을_인터페이스 형식으로 사용해주면 된다.
  • 아래와 같이 선언하면 Personname, age에 관한 타입 선언을 Teacher가 상속받아 사용할 수 있다.
//인터페이스 선언
interface Teacher extends Person{
  subject: string;
}
// 인터페이스 사용
const mathTeacher:Teacher = {
  name: 'su',
  age: 42,
  subject: 'math'
}

이처럼 인터페이스는 확장성이 좋기 때문에, 확장성을 위해 타입별칭보다 인터페이스를 쓰는 걸 추천한다.





2. 타입 별칭이란

  • 타입별칭이란, 특정 타입(number, string 등)이나 인터페이스를 참조할 수 있는 타입 변수를 말한다.
  • 인터페이스처럼 새로운 타입을 생성하는 게 아니라, 이미 정의된 타입을 참조하기 쉽게 별칭을 붙이는 것이다.
  • type이라는 키워드를 이용해 타입을 선언할 수 있다.
type name = string;  //타입별칭
const person: name = 'susan';  //사용

  • 타입 별칭은 인터페이스처럼 속성의 구체적인 타입을 선언할 수 있다.
// 타입 별칭 생성
type Obj = {
  id: number,
  name: string
};
// 타입 별칭 사용
const object: Obj = {
  id: 1,
  name: 'gg'
}





3. 인터페이스와 타입 별칭의 차이

(1) 인터페이스의 특징

  • 인터페이스는 동일한 인터페이스를 여러개 선언할 수 있으며, 하나로 병합된다.
// PersonInterface 인터페이스 선언
interface PersonInterface {
  name: string;
  age: number;  
}
// PersonInterface 인터페이스 중복 선언
interface PersonInterface {
  id: number;  
}
//id, name, age 속성 모두 사용
const lili: PersonInterface = {
  id: 2,
  name: 'lili',
  age: 30
}

  • 하지만, 인터페이스의 경우 데이터의 타입을 바로 확인하기 어렵다.



(2) 타입 별칭의 특징

  • 타입 별칭의 경우, 동일한 타입을 여러번 선언할 수 없다.
type PersonAlias = { //error
  name: string;
  age: number;
}
type PersonAlias = {  //error
  id: number;
}


  • 대신 타입 별칭을 사용하면 해당 타입을 사용한 데이터의 타입을 바로 알 수 있다.
const haha: PersonAlias = {
  name: 'haha',
  age: 30
}



반응형

댓글