ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TypeScript | Interface 인터페이스
    JavaScript/TypeScript 2020. 5. 7. 12:34

    Interface 인터페이스

    타입스크립트에서 인터페이스는 여러 가지 자료형의 타입을 정의하는 용도로 사용

    인터페이스로 객체 타입 정의하기

    interface 키워드를 사용해서 인터페이스로 타입 정의

    interface Person {
        name: string;
        age: number;
    }
    
    const p1: Person = { name: 'mike', age: 23 };
    const p2: Person = { name: 'mike', age: 'ten' }; // 타입 에러
    • Person 인터페이스로 객체 내부에 존재하는 각 속성의 타입 정의
    • 하나 이상의 속성 타입을 만족하지 못하면 타입 에러 발생

    선택 속성

    선택 속성은 객체에 없어도 되는 속성을 말함
    인터페이스에서 선택 속성은 ?(물음표) 기호 사용

    interface Person {
        name: string;
        age?: number;
    }
    const p1: Person = { name: "mike" };
    
    // 선택 속성 대신 유니온 타입으로 undefined를 추가하는 경우
    interface Person {
        name: string;
        age: number | undefined;
    }
    const p1: Person = { name: "mike" }; // 타입 에러
    const p2: Person = { name: "mike", age: undefined };
    • 유니온 타입으로 undefined를 추가하는 경우 선택 속성과 달리 명시적으로 undefined를 입력해야 함

    읽기 전용 속성

    읽기 전용 속성은 값이 변하지 않는 속성을 말함
    인터페이스에서 읽기 전용 속성은 readonly 키워드 사용

    interface Person {
        readonly name: string;
        age?: number;
    }
    const p1: Person = {
        name: 'mike',
    }
    p1.name = 'jonh'; // 컴파일 에러
    • 변수를 정의하는 시점에는 값 할당 가능
    • 읽기 전용 속성의 값을 수정하려고 하면 컴파일 에러가 발생함

    정의되지 않은 속성값을 할당하는 경우

    보통은 객체가 인터페이스에 정의되지 않은 속성값을 갖고 있어도 할당이 가능하지만
    리터럴로 초기화하는 경우에는 타입 에러 발생

    interface Person {
        readonly name: string;
        age?: number;
    }
    
    // 리터럴로 초기화하는 경우
    const p1: Person = {
        name: 'mike',
        birthday: '1997-01-01', // 타입 에러
    }
    const p2 = {
        name: 'mike',
        birthday: '1997-01-01',
    }
    const p3: Person = p2;
    • Person 인터페이스에 정의되지 않은 birthday 속성을 리터럴로 입력하므로 타입 에러 발생
      → 리터럴에서 에러가 발생하는 이유는 프로그래머의 실수일 확률이 높기 때문이며, 이는 타입스크립트의 편의 기능임
    • p2는 Person에 정의되지 않은 속성을 포함하지만 p3에 할당될 때 타입 에러가 발생하지 않음
      → p3 타입이 p2의 타입을 포함하는 더 큰 타입이기 때문('타입 호환성'에서 다룸)

    인터페이스로 인덱스 타입 정의하기

    인터페이스에서 속성 이름을 구체적으로 정의하지 않고 값의 타입만 정의하는 것을 인덱스(index) 타입이라고 함

    interface Person {
        readonly name: string;
        age: number;
        // 인덱스 타입
        [key:string]: string | number;
    }
    const p1: Person = {
        name: 'mike',
        birthday: '1997-01-01',
        age: '25', // 타입 에러
    }
    • 문자열로 된 속성 이름에 대해 값이 문자열 또는 숫자라고 정의
    • birthday 속성을 리터럴로 정의해도 컴파일 에러가 발생하지 않음
    • age는 명시적으로 숫자로 정의했기 때문에 문자열 입력 시 타입 에러 발생

    여러 개의 인덱스를 정의하는 경우

    자바스크립트에서는 속성 이름에 숫자와 문자열을 사용할 수 있는데,
    속성 이름이 숫자인 경우 문자열로 변환된 후 사용됨
    따라서 타입스크립트에서는 숫자인 속성 이름의 값이 문자열인 속성 이름의 값으로 할당 가능한지 검사

    interface YearPriceMap {
        [year: number]: number;
        [year: string]: string | number;
    }
    const yearMap: YearPriceMap = {};
    yearMap[1998] = 1000;
    yearMap[1998] = 'abc'; // 타입 에러
    yearMap['2000'] = 1234;
    yearMap['2000'] = 'million';
    • YearPriceMap 에서 number 는 string | number에 할당 가능하기 때문에 타입 에러가 발생하지 않음
    • 숫자인 속성 이름이 문자열로 변환되기 때문에 숫자 속성의 값이 문자 속성의 값에 포함될 수 있어야 하는 것
    • 속성 이름이 숫자인데 문자열을 값으로 입력하면 타입 에러 발생

    인터페이스로 함수 타입 정의하기

    인터페이스로 함수를 정의할 때는 속성 이름 없이 정의

    interface GetInfoText {
        (name: string, age: number): string;
    }
    const getInfoText: GetInfoText = function(name, age) {
        const nameText = name.substr(0, 10);
        const ageText = age >= 35 ? 'senior' : 'junior';
        return `name: ${nameText}, age: ${ageText}`;
    }

    인터페이스로 클래스 구현하기

    implements 키워드를 사용해서 인터페이스를 클래스로 구현

    interface Person {
        name: string;
        age: number;
        isYoungerThan(age: number): boolean;
    }
    
    class SomePerson implements Person {
        name: string;
        age: number;
        constructor(name: string, age: number) {
            this.name = name;
            this.age = age;
        }
        isYoungerThan(age: number) {
            return this.age < age;
        }
    }
    • 세 개의 속성을 가진 인터페이스 정의
    • implements 키워드를 이용해서 인터페이스를 클래스로 구현
    • 하나의 속성이라도 구현하지 않으면 컴파일 에러 발생
    • name, age 속성은 필수 속성이기 때문에 생성자에서 값을 할당하지 않으면 컴파일 에러 발생

    ※ 타입스크립트에서 클래스의 타입을 정의하기 위해서는 알아야할 내용이 많지만

    리액트에서는 객체지향 프로그래밍을 할 일이 많지 않고

    리액트 훅의 등장으로 클래스형 컴포넌트의 중요성이 낮아짐


    인터페이스 확장

    extends 키워드를 사용해서 인터페이스 확장 가능
    여러 개의 인터페이스를 확장할 수도 있음

    interface Name {
        name: string;
    }
    interface Age {
        age: number;
    }
    interface Korean extends Name, Age {
        isLiveInSeoul: boolean;
    }
    
    /*
    interface Korean {
        name: string;
        age: number;
        isLiveInSeoul: boolean;
    }
    */
    • Name, Age 인터페이스를 확장해서 Korean 인터페이스 생성
    • 확장해서 만들어진 Korean 인터페이스는 주석 처리한 것과 같음

    인터페이스 합치기

    & 기호(교차 타입)를 사용해서 여러 인터페이스를 하나로 합칠 수 있음

    interface Person {
        name: string;
        age: number;
    }
    interface Product {
        name: string;
        price: number;
    }
    type PP = Person & Product;
    const pp: PP = {
        name: 'a',
        age: 23,
        price: 1000,
    }
    • type PP는 합쳐진 두 인터페이스 Person과 Product의 모든 속성값을 포함
    • PP의 타입이 name 속성만 포함하지 않는 것은 PP 타입이 Person과 Product 속성의 교집합이 아니라
      각 인터페이스의 타입이 가질 수 있는 값의 집합에 대한 교집합이기 때문

    참고도서: [실전 리액트 프로그래밍 / 저자_ 이재승 / 출판사_ 프로그래밍 인사이트]

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

    TypeScript | 타입 호환성  (0) 2020.05.07
    TypeScript | 함수형 타입  (0) 2020.05.06
    TypeScript | Enum 열거형 타입  (0) 2020.05.06
    TypeScript | 개요 & 변수 타입  (0) 2020.05.06

    댓글

Designed by Tistory.