ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TypeScript[4] Interface
    Language/TypeScript 2018. 7. 30. 15:59





    - Interface



    Interface 라는 개념은 Java 나 C# 등의 정적 타입 언어에서 이미 많이 쓰이는 개념이다.

    Interface는 클래스에서 구현부가 빠졌다고 이해하면 편하다. 즉, 어떠한 객체가 이러이러한 프로퍼티 혹은 메소드를 가진다고 선언하는 것이다. 실질적인 구현은 이를 구현한다고 선언하는 클래스에 맡긴다.

    TypeScript에서 interface는 새로운 데이터 타입을 만드는 추상데이터 타입으로 사용이 되며 일반 변수,함수,클래스의 type check을 위해 사용된다. Interface를 이용하여 타입을 선언하면 Interface안에 명시된 property의 선언과 method의 구현이 강제되기 때문에 프로그래밍의 일관성을 확보할수 있다.

    *참고로 ES6은 Interface를 지원하지 않고 TypeScript만 지원을 한다.


    1. Basic Example


    interface IBook {

    bookName : String;
    bookAuthor : String;
    }

    let mBook : IBook;

    mBook = {
    bookName:"젊은 베르테르의 슬픔",
    bookAuthor:"괴테"
    };

    console.log(mBook); // { bookName : '젊은 베르테르의 슬픔', bookAuthor : '괴테' }


    간단한 예제이다. IBook Interface가 mBook의 객체의 property의 type check를 하는 모습이다.


    2. Parameter Type Check Example


    interface IBook {
    bookName : String;
    bookAuthor : String;
    }
    function printBookInfo(paramBook:IBook){
    console.log(paramBook.bookName);

    }

    let mBook : IBook = {
    bookName:"젊은 베르테르의 슬픔",
    bookAuthor:"괴테"
    };
    printBookInfo(mBook); // 젊은 베르테르의 슬픔



    함수의 파라미터로 Interface 타입의 객체가 전달되어 사용되었다.

    다음 예제에서부터 머리가 아파온다.


    3. Duck Typing


    interface IBook {

        bookName : String;
    bookAuthor : String;
    }
    function printBookInfo(paramBook:IBook){
    console.log(paramBook.bookName);

    }

    let mBook = {
    bookName:"젊은 베르테르의 슬픔",
    bookAuthor:"괴테",
    bookPrice : 3000
    };

    printBookInfo(mBook);// 젊은 베르테르의 슬픔


    이 코드에서는 bookPrice 라는 Interface에 정의되어지지않은 프로퍼티가 있기때문에 에러가 날꺼라는 생각을 가졌지만

    제대로 컴파일이 이루어지고 결과가 나타난다.


    TypeScript의 중요한 원칙 중 하나는 가지고 있는 값들의 형태를 가지고 type-checking을 수행한다는 것이다.

    다시 말해서 type-checking은 Interface에서 선언된 타입만을 비교하는 것이 아니라 실제 이용될수 있는 형태의 값들을 가고 있느냐 그렇지 않느냐를 따진다.


    위의 예제에서 myBook 객체는 비록 IBook interface type은 아니지만 IBook Interface type을 모두 커버할 수 있는 값들의 형태를 가지고 있다. ( bookName, bookAuthor ) 이러한 경우 myBook 객체는 IBook Interface 타입으로 간주한다는 뜻이다 .


    또 다른 예제를 살펴보자.


    interface Quackable {
    quack() : void;
    }

    class Duck implements Quackable {
    quack(){
    console.log("꽥");
    }
    }

    class Person {
    quack(){
    console.log("나도 꽥!");
    }
    }

    function makeSomeNoiseWith(duck : Quackable){
    duck.quack();
    }

    makeSomeNoiseWith(new Duck()); // 꽥
    makeSomeNoiseWith(new Person()); // 나도 꽥!

     

    Duck 클래스는 Quackable Interface 를 구현한 클래스이기에 정상적으로 결과가 출력이 되는것은 알겠지만 

    Person 클래스는 Quackable Interface 를 구현한다고 선언하지 않았음에도 불구하고 결과가 출력이 된다.


    전 예제에서 말했듯이 TypeScript은 선언된 타입을 비교하는 것이 아니기에 Quackable Interface에 quack 메소드만 구현되어 있다면 Quackable 객체로 보는것이다 .

    클래스의 상속이나 Interface의 구현으로 타입을 구분하는 것이 아니라 객체가 특정 타입에 걸맞는 property 와 method를 가지고 있으면 해당 type 으로 간주한다는 것으로 생각하면 된다.



    4. Optional Properties


    TypeScript Interface의 모든 프로퍼티와 메소드는 구현되는 클래스 혹은 구현 객체에서 기본적으로 모두 재정의가 되어야 한다.

    하지만 Optional Property(property 중  가 붙어있는 property를 의미)를 이용하면 해당 property는 재정의하지 않아도 상관없다.


    interface Shape {
    width? : number;
    height? : number;
    radius? : number;
    getArea() : number;
    }

    class Rect implements Shape {
    width : number;
    height : number;

    constructor(width,height){
    this.width=width;
    this.height=height;
    }
    getArea() : number {
    return this.width*this.height;
    }
    }

    class Circle implements Shape {
    radius : number;

    constructor(radius){
    this.radius=radius;
    }
    getArea() : number{
    return this.radius*this.radius*Math.PI
    }

    } 



    5. Readonly Properties



    readonly 키워드를 이용해 객체가 처음 생성되는 시점에만 property들을 수정가능하도록 설정하였다.

    한번 값이 세팅되면 그 후에는 수정할수 없게 된다.


    interface Point{
    readonly x : number;
    y : number;
    }
    let p1 : Point = {x:1 , y:2 };

    p1.x=3; // error


    TypeScript는 또 ReadonlyArray<T> 형태의 Array를 지원한다. 이름에서 의미하는 것처럼 생성된 후에는 Array를 변경할수 없다.



    let arr : number[] =[1,2,3,4];

    let roArray : ReadonlyArray<number>=arr;

    roArray[0]=100; // error

    roArray.push(100); // error

    arr= roArray; // error

    arr= roArray as number[]; // 가능


    마지막 코드는 Type Assertion(타입 단언)으로 roArray 타입을 number[]로 변환시킨 코드이다.

    추후에 Type Assertion에 관해 공부해보자.


    6. Function Types


    interface 는 function의 type 을 지정하는데 사용될수 있다.


    interface myType {
    (myName : string, myAge : number) : void
    };

    let myIntroduce:myType=function(myName: string,myAge:number){
    console.log(`이름 : ${myName} , 나이 : ${myAge}`);
    }

    myIntroduce("이민우",25); //이름 : 이민우 , 나이 : 25




    7. Indexable Types


    JavaScript 의 객체는 프로퍼티 접근자를 두가지 제공한다. 하나는 점 표기법(Dot notation)이고, 다른 하나는 괄호 표기법(Bracket notation)이다. 기본적으로 점 표기법을 자주 사용하기는 하지만, 동적으로 프로퍼티에 접근하려는 경우 괄호 표기법을 사용하기도 한다.



    let obj= {
    myName : "이민우",
    myAge : 25
    };

    console.log(obj.myName);
    //점 표기법(dot notation)

    let keys = Object.keys(obj);

    for(let i=0;i<keys.length;i++){
    console.log(obj[keys[i]]);
    // 괄호 표기법(bracket notation)

    }


    JavaScript로는 문법에러가 없는 코드지만  TypeScript에서는 코드에러가 발생한다.

    에러 내용은 


    Element implicitly has an 'any' type because type '{ myName: string; myAge: number; }' has no index signature.


    index signature 을 가지고 있지 않아 암시적으로 any 타입을 사용한다는 것이다. 이 에러는 tsconfig.json 에서 옵션중 noImplicityAny 속성을 true(default 값)으로 설정했을때 발생한다.


    그렇다면 에러 해결방법은 두가지이다.

    첫번째는 index signature 를 가지게 하는 방법 , 두번째는 tsconfig.json 에서 noImplicitAny 속성 값을 false 로 바꾸는 방법이 있다.

    하지만 TypeScript는 any 타입을 지양하기 때문에 첫번째 방법이 좀더 효과적이라고 볼수 있다.

    Interface로 index signature를 설정해서 사용할수 있는데 이것을 Indexable Type이라고 한다.


    아래의 예제와 같이 union type 으로 설정이 가능하다.


    interface Iobj{
    [idx : string] : string | number;
    }

    let obj : Iobj= {
    myName : "이민우",
    myAge : 25
    };

    console.log(obj.myName); // 이민우


    let keys = Object.keys(obj);

    for(let i=0;i<keys.length;i++){
    console.log(obj[keys[i]]); // 이민우 25

    }




    interface Indexable {
    [key : string] : any;
    }

    const dict : Indexable = {
    foo : 1,
    bar : 2
    };

    Object.keys(dict).forEach(k=>console.log(dict[k])); // 1 2



    https://hyunseob.github.io/2016/10/17/typescript-interface/


    https://moon9342.github.io/typescript-interface


    'Language > TypeScript' 카테고리의 다른 글

    TypeScript[6] Function  (0) 2018.08.04
    TypeScript[5] Class  (0) 2018.07.30
    TypeScript[3] - 변수 선언  (0) 2018.07.23
    TypeScript[2] - 기본 타입  (0) 2018.02.16
    TypeScript[1] - 설치,tsconfig.json  (0) 2018.02.16
Designed by Tistory.