ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TypeScript] Type Compatibility ( 타입 호환성 )
    Computer Science 2023. 12. 9. 23:02

    타입 호환성이란?

    두 가지 타입 간에 비교를 통해 값이 할당 가능한지 여부를 나타내는 것 입니다. 즉 다른 타입이 해당 타입안에 들어올 수 있는지 판단합니다.

     

    TypeScript의 타입 호환성은 명목적 타이핑 ( nominal typing )이 아닌 구조적 서브 타이핑 ( subtyping ) 을 기반으로 합니다.

    구조적 타이핑이란 오직 맴버만으로 타입을 확인하는 방식입니다.

    interface test1 {
        test: string;
    }
    
    class test2 {
        test: string;
    }
    
    let test3: test1;
    
    test3 = new test2(); // 맴버가 같기에 가능합니다.

     

    함수의 비교

    let first = (test: string) => "test";
    let second = (test: string, test2: string) => "test";
    
    second = first; // OK
    first = second; // Error

     

    함수의 비교에서는 매개변수를 서로 비교합니다.

    second는 first의 모든 매개변수를 가지고 있기에 호환이 가능하지만 first는 second의 test2 를 가지고 있지 않기에 에러를 반환합니다.

     

    열거형의 비교

    enum Test1 {
        A,
        B,
        C,
    }
    
    enum Test2 {
        A = 1,
        B,
        C,
    }
    
    let test = Test1.A;
    test = Test1.B; // OK
    test = Test2.A; // Error

     

    열거형은 단순하게 다른 열거형 타입의 열거형과는 호환되지 않습니다. 다만 같은 열거형 내에서는 호환이 가능합니다.

     

    클래스의 비교

    class Test1 {
        test: string;
        testFunc() {
            console.log("test");
        }
    
        constructor(test1: string, test2: string) {
            this.test = test1;
        }
    }
    
    class Test2 {
        test: string;
        static test2: string;
        testFunc() {
            console.log("test");
        }
    
        constructor(test1: string) {
            this.test = test1;
        }
    }
    
    let firstTest: Test1;
    let secondTest: Test2;
    
    firstTest = secondTest; // OK
    secondTest = firstTest; // OK

     

    클래스 타입의 비교는 오직 인스턴스의 맴버만 비교를 진행합니다.

    즉 정적 맴버 ( static ) 과 생성자 ( constructor ) 는 호환성에 영향을 주지 않습니다.

     

    제네릭의 비교

    interface Test<T> {}
    let test1: Test<string>;
    let test2: Test<number>;
    
    test1 = test2; // OK
    test2 = test1; // OK
    
    
    
    interface Test<T> {
        test: T;
    }
    let test1: Test<string>;
    let test2: Test<number>;
    
    test1 = test2; // Error
    test2 = test1; // Error

     

    제네릭 타입에서 중요한 것은 결국 결과 타입입니다. 들어가는 Type이 중요한 것이 아닌 결과 인자를 비교합니다.

    따라서 처음 호환은 전부 가능하지만 두번째부터는 불가능합니다.

     

    Freshness ( 신선도 ) 란

    type Test = {
        name: string;
        age: number;
    }
    
    function testFunction(test: Test) {
        console.log(test.name);
    }
    
    let testInput = {
        name: 'test',
        age: 10,
        test: 'test'
    }
    
    testFunction(testInput); // OK
    testFunction({ name: 'test', age: 10 }); // OK
    testFunction({ name: 'test', age: 10, test: 'test' }); // Error

     

    TypeScript는 신선도라는 개념을 제공하는데, 모든 object literal 은 초기에 "fresh" 로 간주합니다.

    다만 type assertion ( 타입 단언 )을 하거나, 타입 추론에 의해 object literal 의 타입이 확장되면 "fresh" 가 사라집니다.

    "fresh" 상태에서는 타입호환을 허용하지 않습니다. 그렇기에 위와 같은 경우에서 마지막에는 Error가 발생합니다.

Designed by Tistory.