JS/JavaScript&TypeScript

JavaScript&TypeScript 10. 인터페이스&타입 별칭

shin96bc 2022. 4. 3. 00:07

(1) 인터페이스 와 타입 별칭 ( TypeScript )

     Github: https://github.com/SHIN96BC/JavaScript-TypeScript-Concept-2022/tree/main/10_Interface

     1) 인터페이스 ( interface )
          <1> 객체타입을 지정한다. ( 객체는 이런 규격이어야 한다고 지정 )
               1> interface IUser {
                       readonly id : number;
                       readonly name : Name; ( 여기에 타입은 아래에서 타입 알리아스로 만든 타입이다 )
                       email: string;
                       receiveInfo: boolean;
                       active : YesOrNo; 
                       address?: string;
                  }
          <2> 인터페이스는 타입알리아스와 섞어서 쓸수도 있다.

          <3> readonly 란 읽기 전용 이라는 의미이다.

          <4> address?: string -> 이런식으로 ? 가 붙어있는 것은 이 객체를 만드는데 address 라는 속성이 

                                          있어도 되고, 없어도 된다는 의미이다. ( 옵셔널 )

          <5> extends ( 확장하다. 인터페이스를 합치는 기능. 상속과 유사한 기능 )
               1> interface IUserProfile extends IUser{
                       profileImage: string;
                       github?: string;
                       twitter?: string;
                  }

               2> extends 는 위와 같이 IUserProfile 라는 인터페이스는 IUser 의 속성을 모두 가지고 있고, 

                    또한 자기 개별 속성도 가지고 있는 객체들이 여러개 존재할 경우, IUser 의 속성들을

                    반복적으로 작성해야하는 코드의 중복을 해결할 수 있다.

               3> 타입 알리아스와 인터페이스 둘다 extends 할 수 있다. ( 섞어서 사용 가능 )

               4> 다중 상속 가능
                    ex) interface IStyle extends Color, Display, Geometry{
                             tagName : string;
                        }

          <6> 구체적인 이름은 지정하지 않고, key값 ( 이름 ) 은 어떤 타입이고,

                  value값 ( 데이터 ) 은 어떤 타입이다. 라고 지정할 수도 있다.
               1> 객체 규격
                    ex) interface IOnlyNumberValueObject  {
                             [key:string]:number;
                        }
                    1. 여기서 key 는 문자열 타입이고, 그 key 값에 해당하는 value 값은 숫자 타입이라는 뜻이다.

               2> 함수 규격
                    ex) interface IGetApi {
                             (url:string, search?: string): Promise<string>
                        }
                    1. 여기서 () 안에는 인자( 파라미터 ) 의 타입을 지정하고, : 을 쓰고 

                        반환타입을 지정해주면 된다.

          <7> 인터페이스의 모든 속성들은 public 이다. 그래서 그걸 구현한 class 에서 속성을 private 나 

                 다른 제한자로 바꿀 수 없다.

          <8> class 의 생성자 규격을 지정할 수 있다.
               1> interface IRectConstruct {
                       new (x: number, y: number, width:number, height:number): IRect;
                  }

     2) 타입 알리아스 ( 타입 별칭, Type Alias ) ( 컴파일 타임 )
          <1> 기본형 ( 일반적인 타입을 지정)
               1> type Name = string;
                    ef) 나는 이름 이라고 하는 속성을 문자열로 쓸건데 그걸 Name 이라고 명시할거야. 

                         이렇게 해석할 수 있다.
          <2> 함수에 타입지정
               1> type FooFunction = () => string;
                    cf) 함수를 만드는데 그 함수는 인자 없이 반환값이 스트링이다. 라고 명시한 것이다.

          <3> 리터럴 타입 ( 특정 문자열을 지정 )
               1> type YesOrNo = 'Y' | 'N';  
               2> | 는 유니온 타입이라고 해서 둘중 하나가 들어갈 수 있다는 의미이다.

          <4> 객체 타입
               1> type TUser = {
                       readonly id : number;
                       readonly name : string;
                       email: Email;
                       receiveInfo : boolean;
                       active : YesOrNo;  ( 타입 알리아스 안에서 타입 알리아스 사용 )
                       address?: string;
                  }
               cf) 인터페이스와 차이는 = 이 있고 없고 차이 말고는 똑같다.

               2> 일반 타입 사용가능

               3> 타입 알리아스 안에서 타입 알리아스도 사용 가능

               4> 타입 알리아스의 객체 타입 역시 옵셔녈 ( ? ) 기능을 사용할 수 있다.

               5> 타입 알리아스의 객체 타입 역시 extends 와 동일한 기능이 있다. 

                     ( 인터페이스와 거의 동일하다 )
                    ex) type TUserProfile = IUser & {
                             profileImage: string;
                             github?: string;
                             twitter?: string;
                        }

                    cf) 타입 알리아스와 인터페이스 둘다 섞어서 사용 가능하다.

                    cf) 인터페이스와 동일하게 여러개를 합칠 수 있다.
                         ex) type TStyle = Color & Display & Geometry & {
                                  tagName : string;
                             }
               6> 구체적인 이름은 지정하지 않고, key값 ( 이름 ) 은 어떤 타입이고,

                     value값 ( 데이터 ) 은 어떤 타입이다. 라고 지정할 수도 있다.
                    1. 객체 규격 ( 인터페이스와 거의 동일하다 )
                         type TOnlyBooleanValueObject = {
                              [prop:string]: boolean;
                         }

                    2. 함수 규격 ( 인터페이스와 거의 동일하다 )
                         type TGetApi = {
                              (url:string, search?: string): Promise<string>
                         }
                    cf) 여기서 주의해야할 사항은 타입 알리아스에서 함수 타입을 지정할때는 에로우( => ) 를 

                         사용했지만, 객체 타입으로 함수의 규격을 정의할 때는 => 대신에 : 을 사용한다.

          <5> type 은 컴파일 타임에 이 값이 들어가는지 안들어가는지, 

                 그런 코드가 있는지를 확인하는 용도이다.

     3) enum 타입( 런타임 )
          <1> enum 은 실제 데이터이다. 그래서 런타임에 {} 안에 써있는 값이 실제로 들어간다
                 문자열이 들어가는 것은 아니고, 지정된 인덱스에 들어간다.

                 ( 지정된 값이 없으면 순서대로 들어간다. )
          ex) enum DayOfTheWeek {'월', '화', '수', '목', '금', '토','일'};


     4) type 알리아스 와 enum 타입 의 차이점
          <1> enum 타입은 특정 값으로 제한하는 기능은 유사하지만 실제 데이터이고,  
              type 은 컴파일 타임에 타입을 검사하는 용도로 사용된다는 차이점이 있다.

     5) 인터페이스 와 타입 알리아스는 어떤 원칙에 따라 선택해서 사용해야 할까? ( 차이점 )
          <1> 인터페이스는 이름 중복을 허용 한다. ( 두개를 합쳐서 하나의 인터페이스로 인식한다 )
               1> interface IUser {
                       readonly id : number;
                       readonly name : Name;
                       email: string;
                       receiveInfo: boolean;
                       active : YesOrNo; 
                  }

                  interface IUser{
                       address?: string;
                  }
               2> 이런 사용법도 가능은 하지만, 인터페이스 안에 요소들을 확인하기가 까다로울 수 있으므로 

                    특별한 경우가 아니면 사용하지 않는 것이 좋다. ( 하나에 다 몰아넣는 방식이 좋다 )

          <2> 타입 알리아스는 이름 중복을 허용하지 않는다. ( 이름 중복으로 에러 발생 )
               1> type TUser = {
                       readonly id : number;
                       readonly name : string;
                       email: Email;
                       receiveInfo : boolean;
                       active : YesOrNo;
                  }

                  type TUser = {
                       address?: string;
                  }

          <3> 기본적으로는 아무거나 사용해도 문제없다.

          <4> 인터페이스에 없는 기능을 타입 알리아스는 제공하고 있다.
               1> 구체적인 타입을 명시하는 것
                    ex) type Name = string;
                        type Email = string;
                        이런식으로 string 을 이름에 사용할건지, 이메일에 사용할건지 구체적으로 

                        그 타입의 이름을 지정하는 것은 타입 알리아스만 가능하다.

          <5> 결론
               1> 데이터를 표현할 때는 타입 알리아스가 좋다.

               2> 클래스나 메소드와 같은 구체적인 행위까지 포함된 객체를 디자인 할때는 인터페이스가 좋다.

     6) 타입을 제한하지 않고 모든 타입이 들어올 수 있게 하려면 any 를 사용한다.