ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TypeScript | 타입 호환성
    JavaScript/TypeScript 2020. 5. 7. 12:46

    타입 호환성

    타입 호환성이란 어떤 타입을 다른 타입으로 취급해도 되는지 판단하는 것
    타입 A를 타입 B로 취급해도 되는 것을 할당 가능하다고 하며
    타입 A가 타입 B의 서브타입(subtype)이라고 표현하기도 함

    정적 타입 언어의 가장 중요한 역할은 타입 호환성을 통해 컴파일 타임에 호환되지 않는 타입을 찾아내는 것


    숫자와 문자열의 타입 호환성

    숫자와 문자열 타입은 서로 포함 관계에 있지 않기 때문에 서로 할당 가능하지 않음
    반면 숫자의 집합은 number | string 값의 집합에 포함되기 때문에 숫자는 number | string 타입에 할당 가능

    function func1(a: number, b: number | string){
        const v1: number | string = a;
        const v2: number = b; // 타입 에러
    }
    function func2(a: 1 | 2){
        const v1: 1 | 3 = a; // 타입 에러
        const v2: 1 | 2 | 3 = a;
    }
    • number는 number | string에 할당 가능
    • 1 | 2 는 1 | 2 | 3 에 할당 가능
      2가 1 | 3 에는 포함되지 않기 때문에 func2의 v1에서 타입 에러 발생

    인터페이스 타입 호환성

    타입스크립트는 값 자체의 타입보다는 값이 가진 내부 구조에 기반해서 타입 호환성을 검사하는데
    이를 덕 타이핑(duck typing) 또는 구조적 타이핑(structural typing)이라고 함

    인터페이스 할당 조건

    인터페이스 A가 인터페이스 B로 할당 가능하려면 다음 조건을 만족해야 함
    1. B에 있는 모든 필수 속성의 이름이 A에도 존재해야 함
    2. 같은 속성 이름에 대해, A의 속성이 B의 속성에 할당 가능해야 함
    interface Person {
        name: string;
        age: number;
    }
    interface Product {
        name: string;
        age: number;
    }
    const person: Person = { name: 'mike', age: 23 };
    const product: Product = person;
    • Person과 Product는 이름은 다르지만 내부 구조가 같기 때문에 Person과 Product는 서로 할당 가능
    • 많은 수의 정적 타입 언어에서는 위와 같이 할당할 수 없지만,
      타입스크립트는 구조적 타이핑을 사용하기 때문에 할당이 가능함
    • 만약 Person에 age 속성이 없다면 Person은 Product에 할당 가능하지 않음
    • 속성이 많을수록 타입에 더 많은 제약을 가하는 것이고, 이는 해당 타입의 값의 집합이 작아지는 것을 의미함

    선택 속성이 타입 호환성에 미치는 영향

    다음과 같이 Person의 age가 선택 속성이라면 Person은 Product에 할당 가능하지 않음

    interface Person {
        name: string;
        age?: number;
    }
    interface Product {
        name: string;
        age: number;
    }
    const person: Person = { name: 'mike', };
    const product: Product = person; // 타입 에러
    • age가 선택 속성이면 Person 값의 집합은 Product 값의 집합보다 커짐
      → Person 인터페이스의 age속성에 대한 제약을 덜 가하는 것이기 때문
    • 만약 Product의 age속성이 선택 속성이었다면
      Person 값의 집합보다 Product 값의 집합이 더 커지기 때문에 Person은 Product에 할당 가능함

    추가 속성과 유니온 타입이 타입 호환성에 미치는 영향

    추가 속성이 있으면 값의 집합은 더 작아지고, 반대로 유니온 타입이 있으면 값의 집합은 더 커짐

    interface Person {
        name: string;
        age: number;
        gender: string;
    }
    interface Product {
        name: string;
        age: number | string;
    }
    • 추가 속성이 있으면 값의 집합은 더 작아지므로 Person을 Product에 할당하는 데는 문제가 없음
    • 유니온 타입으로 속성 타입의 범위가 넓어지면 값의 집합은 더 커지기 때문에
      역시 Person을 Product에 할당하는 것에 문제가 되지 않음

    함수의 타입 호환성

    함수는 호출 시점에 문제가 없어야 할당 가능

    함수 할당 조건

    다음은 함수 타입 A가 함수 타입 B로 할당 가능하기 위한 조건
    1. A의 매개변수 개수가 B의 매개변수 개수보다 적어야 함
    2. 같은 위치의 매개변수에 대해 B의 매개변수가 A의 매개변수로 할당 가능해야 함
    3. A의 반환값은 B의 반환값으로 할당 가능해야 함
    type F1 = (a: number, b: string) => number;
    type F2 = (a: number) => number;
    type F3 = (a: number) => number | string;
    let f1: F1 = (a, b) => 1;
    let f2: F2 = a => 1;
    let f3: F3 = a => 1;
    f1 = f2;
    f2 = f1; // 타입 에러
    f2 = f3; // 타입 에러
    • F2보다 F1의 매개변수 개수가 더 많으므로 F1은 F2로 할당 가능하지 않음
    • F3의 반환 타입은 F2의 반환 타입으로 할당 가능하지 않으므로 F3는 F2로 할당 가능하지 않음

    배열의 map 메서드를 통해 살펴보는 함수의 타입 호환성

    function addOne(value: number) {
        return value + 1;
    }
    const result = [1, 2, 3].map<number>(addOne);
    // (value: number, index: number, array: number[]) => number
    • addOne 함수는 map 메서드의 매개변수로 할당 가능
    • map 메서드 옆의 < number > 제네릭은 매개변수 함수의 반환 타입을 의미
    • 주석은 map 메서드가 입력받는 함수의 타입을 의미하며, addOne 함수는 이 타입에 할당 가능
    • 함수의 타입 호환성은 호출하는 쪽에서 생각하면 이해하는 데 도움이 됨

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

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

    TypeScript | Interface 인터페이스  (0) 2020.05.07
    TypeScript | 함수형 타입  (0) 2020.05.06
    TypeScript | Enum 열거형 타입  (0) 2020.05.06
    TypeScript | 개요 & 변수 타입  (0) 2020.05.06

    댓글

Designed by Tistory.