[TypeScript] 타입 추론, 타입 호환, 타입 별칭

wonyu·2022년 6월 12일
0

typescript

목록 보기
3/3

타입 추론(Type Inference)

  • 타입스크립트가 코드를 해석해나가는 동작
let x = 3;
  • 위 코드에서 x 의 타입을 따로 지정하지 않더라도 xnumber 로 간주된다. 변수, 속성, 인자의 기본 값, 함수의 반환 값 등을 설정할 때 이와 같은 타입 추론이 일어난다.

가장 적절한 타입(Best Common Type)

  • 몇 개의 표현식을 바탕으로 타입을 추론해서 best common type을 결정하게 된다.
    let x = [0, 1, null];
    
    // let x: (number | null)[]

문맥상 타이핑(Contextual Typing)

  • 타입스크립트에서 타입을 추론하는 또 하나의 방식
  • 코드의 위치(문맥)을 기준으로 타입을 결정
  • 예시
    window.onmousedown = function(mouseEvent) {
      console.log(mouseEvent.button);
      console.log(mouseEvent.kangaroo);  // error
    }
    • 타입스크립트 검사기 관점에서 window.onmousedown 에 할당되는 함수의 타입을 추론하기 위해 window.onmousedown 의 타입을 검사한다. 타입 검사가 끝나면 함수의 타입이 마우스 이벤트와 연관이 있다고 (mouseEvent 의 타입이 MouseEvent 라고) 추론한다. 따라서 mouseEventkangaroo 속성이 없다고 결론을 내린다.

타입스크립트의 타입 체킹

  • 타입스크립트 컴파일러는 컴파일 시점에 Duck Typing과 같은 방식으로 타입을 검사해서 컴파일 에러를 내준다. 이것이 Structural Typing이다.
  • Duck Typing?
    • Duck Test로부터 유래한 일종의 프로그래밍 패턴
      • Duck Test 비유: 그것이 오리인지 100% 확실하지는 않다. 하지만 오래처럼 생겼고, 오리처럼 걷고, 오리처럼 헤엄치며, 오리처럼 꽥꽥 소리를 낸다. 이 정도의 추론 단서라면 내가 보는 것이 오리라고 판단해도 무리는 없을 것이다.
  • Structural Typing?
    • 컴파일 시점에 Duck Typing을 적용한 것
    • 어떤 타입의 이름이나 그것의 위치와 상관 없이 내부적으로 같은 구조를 갖고 있다면 두 타입이 같다고 보는 것

타입 호환 (Type Compatibility)

  • 타입스크립트 코드에서 특정 타입이 다른 타입에 잘 맞는지
  • 예시
    interface Ironman {
    	name: string;
    }
    
    class Avengers {
    	name: string;
    }
    
    let i: Ironman;
    i = new Avengers();  // structural typing에 의해 에러가 발생하지 않는다.

Enum 타입 호환 주의 사항

  • Enum 타입은 number 타입과 호환되지만 Enum 타입끼리는 호환되지 않음

Class 타입 호환 주의 사항

  • Class 타입은 Class 타입끼리 비교할 때 static member와 constructor를 제외하고 속성만 비교
    class Hulk {
      handSize: number;
      constructor(name: string, numHand: number) {}
    }
    
    class Captain {
      handSize: number;
      constructor(numHand: number) {}
    }
    
    let h: Hulk;
    let c: Captain;
    
    // 속성이 같으므로(둘 다 handSize를 가짐) 서로 할당 가능
    // 만약 한 클래스가 다른 클래스에 없는 속성을 가진다면 해당 속성이 없는 쪽에서는 할당 불가
    h = c;
    c = h;

Generic 타입 호환 주의 사항

  • 속성이 없을 때는 타입 인자 <T> 가 속성에 할당되었는지를 기준으로 체크
    interface Empty<T> {}
    let x: Empty<number>;
    let y: Empty<string>;
    
    x = y;
  • 인터페이스에 속성이 있어서 제네릭의 타입 인자가 속성에 할당된다면 다른 타입으로 간주

타입 별칭 (Type Aliases)

  • 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수
    // 타입 별칭을 사용할 경우
    type MyName = string;
    const name: MyName = 'YJ';
    
    // 타입 별칭을 사용하지 않을 경우
    const name: string = 'YJ';
  • string , name 과 같은 간단한 타입뿐만 아니라 인터페이스, 제네릭에도 사용할 수 있음

타입 vs 인터페이스

  • 가장 큰 차이점은 타입의 확장 가능 여부 (인터페이스: 확장 가능, 타입: 확장 불가능)
  • 가급적 확장 가능한 인터페이스로 선언하면 좋음

0개의 댓글