Post

[TypeScript] 인터페이스

[TypeScript] 인터페이스

데브타스

인터페이스

  • 앞서 배운 타입 별칭의 개념을 비교하며 살펴본다.
  • 타입 별칭으로 지정할 수 있는 객체인터페이스로도 설정 가능
  • 따라서, 객체 타입만이 인터페이스로 설정 가능 (원시 타입 불가!)
  • interface 키워드를 사용하여, 지정
  • 예시

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
      // 객체 타입을 지정 시 사용 (나만의 객체 타입)
      interface User {
        name: string;
        age: number;
      }
        
      const user1: User = {
        name: "jaegeon",
        age: 20,
      };
      -------------------------------------------
      interface User {
        name: string;
        age: number;
        greet(): void;
      }
      const user1: User = {
        name: "jaegeon",
        age: 26,
        greet() {
          console.log(`${this.name}, ${this.age}`);
        },
      };
      user1.greet();
    

인터페이스 특징

  1. 타입 별칭과 달리, 상세 스펙이 보이지 않음.

    Image

  2. 타입 별칭과 달리, 인터페이스명 중복 가능.
    이름이 같다면, 자동으로 합쳐줌. (선언 병합)

    Image

    → 주의사항: 인터페이스 내의 각 속성의 타입이 달라서는 안된다!

    Image

인터페이스 - 함수

  • 함수를 인터페이스로 지정하면 다음과 같다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      // 함수 별칭의 경우
      type SumFunc = (n1: number, n2: number) => number;
        
      // 인터페이스로 함수 정의
      interface SumFuncInterface {
        (n1: number, n2: number): number;
      }
        
      const sum: SumFuncInterface = (n1, n2) => n1 + n2;
    

→ 주의사항: 인터페이스로 지정한 함수에는 옵셔널 파라미터 ?를 지정할 수 없다.

  • 함수를 지정 시에, name과 같은 함수에 원래 존재하는 속성을 사용 가능!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      // 함수 별칭의 경우
      type SumFunc = (n1: number, n2: number) => number;
        
      // 인터페이스로 함수 정의
      interface SumFuncInterface {
      	name: string;
        (n1: number, n2: number): number;
      }
        
      const sum: SumFuncInterface = (n1, n2) => n1 + n2;
    
  • 함수에 원래 존재하는 속성들 (caller는 안됨!)

    Image

인터페이스 상속

  • 자바스크립트(타입스크립트)에서 인터페이스를 상속할 수 있음
  • extends 키워드를 사용하여, 상속을 표현
  • 문법적으로도, 인터페이스 상속 > 타입 별칭 & 용이.
  • 공통으로 들어가는 부분을 각각의 인터페이스 사용할 때 용이.
  • 예시

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
      interface Animal {
        name: string;
      }
        
      interface Dog extends Animal {
        bark(): void; // 왈왈
      }
      const dog: Dog = {
        name: "퍼피",
        bark() {
          console.log("왈왈");
        },
      };
        
      interface Cat extends Animal {
        bark(): void; // 냐옹
      }
      const cat: Cat = {
        name: "냥이",
        bark() {
          console.log("냐옹");
        },
      };
    
  • 다중 상속도 컴마로 구분하여 가능하다!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
      interface A {
        a: string;
      }
      interface B {
        b: number;
      }
      interface C extends A, B {
        c: boolean;
      }
      const cValue: C = {
        a: "a",
        b: 121,
        c: true,
      };
    
  • 타입 별칭과 인터섹션 파라미터 &로도 유사하게 사용 가능!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      type A = {
        a: string;
      };
      type B = {
        b: number;
      };
      type C = A &
        B & {
          c: boolean;
        };
      const cValue: C = {
        a: "a",
        b: 121,
        c: true,
      };
    



인덱스 시그니처

  • 다음 코드는 옵셔널 파라미터 ?를 사용하지 않으면 속성 삭제 불가
    이외에, 속성 추가와 수정도 불가

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      const obj: {
        name: string;
        age?: number;
      } = {
        name: "jaegeon",
        age: 26,
      };
        
      obj.gender = "male";
      delete obj.age;
    

인덱스 시그니처

  • 범용적인 타입 지정 방식
  • 앞선 문제의 해결책으로 인덱스 시그니처를 사용.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      const obj: {
        [key: string]: string | number;
      } = {
        name: "jaegeon",
        age: 26,
      };
        
      obj.gender = "male";
      delete obj.age;
    
  • 객체의 속성을 자유롭게 추가하거나 변경 가능!
  • 단, 명확한 타입 명시는 불가!

    Image

  • 따라서, 섞어서 사용하면 해당 문제를 해결할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      const obj: {
        name: string;
        age: number;
        [key: string]: string | number;
      } = {
        name: "jaegeon",
        age: 26,
      };
        
      const name1 = obj.name;
      name1.toUpperCase();
    

[참고] 헝가리안 표기법

  • 다음과 같이, 식별자의 타입이 다르나, 이름이 같아서 문제 발생

    Image

  • 따라서, 헝가리 출신 개발자가 다음과 같이, 식별자 작성법 제시.
    타입을 밝혀서 이름을 짓는 헝가리안 표기법

    number: num → nNum

    string: name → strName

    type: User→ TUser

    interface: User→ IUser

    → But, 오늘날에는 위와 같은 방법 권장 X

  • 이유: 식별자의 타입의 변동 가능성이 있음 → 잘못된 정보 제공 우려

→ 따라서, 오늘날에는 이름을 의미있게 지어주는게 추세이다.



구조적 타이핑

  • 타입스크립트는 이름으로 구분하는 것이 아닌, 내부 구조로 구분함.
  • 이름이 달라도 구조가 같다면, 상호 호환이 됨.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
      type Car = {
        name: string;
        speed: number;
      };
      type Vehicle = {
        name: string;
        speed: number;
      };
        
      let car: Car = { name: "MBW", speed: 100 };
      let vehicle: Vehicle = { name: "HONDA", speed: 200 };
        
      function printValue(obj: Car) {
        console.log(`${obj.name}, ${obj.speed}`);
      }
        
      printValue(vehicle);
    

    위와 같이, 이름이 달라도 내부 구조가 같아. 다른 타입의 이름을 사용해도 무방.

많은 속성과 적은 속성

  • 다음과 같이, name 속성이 포함된 두 객체에서
    더 많은 속성을 포함한 객체가 적은 속성을 포함한 객체로 할당될 수 있음!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      type Car = {
        name: string;
        speed: number;
      };
      type Vehicle = {
        name: string;
      };
        
      let car: Car = { name: "MBW", speed: 100 };
      let vehicle: Vehicle = { name: "HONDA" };
        
      vehicle = car; // 많은 속성이 적은 속성의 객체로 할당 가능
      console.log(vehicle);
      console.log(vehicle.speed); 
      // 담겼어도, speed 속성은 Vehicle에 없으므로 출력 불가
    

✏️ 총정리

  • 단순한 객체의 구조 정의 → 인터페이스
  • 유니언, 튜플, 기본 타입, 함수 → 타입 별칭
  • API 응답 값 → 타입 별칭
  • 서로가 서로의 재료가 될 수 있음.

    차이점타입 별칭인터페이스
    선언하는 문법type Type = …interface Type {…}
    정의 가능 범위모든 타입객체 타입만
    추가 기능-선언 병합, extends 상속
This post is licensed under CC BY 4.0 by the author.