[TypeScript] 타입 호환

종현·2024년 1월 5일

[TypeScript]

목록 보기
13/19

타입 호환이란?

  • 서로 다른 타입이 2개 있을 때 특정 타입이 다른 타입에 포함되는지를 의미한다.

let a: string = 'hi';
let b: 'hi' = 'hi';

// a는 string타입, b는 'hi'타입 이지만 큰 범위의 string타입에 hi타입을 대입하는 것은 가능하지만 반대로는 에러가 발생한다. 
a = b; 

let c: string = 'hi';
let d: 'hi' = 'hi';

d = c; // 에러 발생

다른 언어와의 차이점

구조적 타이핑

  • 타입의 유형보다 타입의 구조로 호환 여부를 판별하는 언어적 특성을 의미한다.

  • me변수와 son변수에 타입 별칭과 인터페이스를 사용하여 타입을 정의했지만 구조적으로 동일한 속성과 값을 가지고 있기 때문에 호환이 가능하여 에러가 발생하지 않는다.

  • 하지만 속성이 다르거나 값이 다르다면 에러가 발생하게 된다.

type Me = {
  lastName: string;
}

interface Son {
  laseName: sting;
}

let me: Me = {
  lastName: 'Lee';
}

let son: Son = {
  lastName: 'Lee';
}

son = me;

객체 타입의 호환

  • 객체 타입은 타입 유형에 관계없이 동일한 이름의 속성을 갖고 있고 해당 속성의 타입이 같으면 호환이 가능하다.

  • 아래 코드와 같이 동일한 타입을 가진 속성이 1개라도 있다면 호환이 가능하다.

  • son변수는 isBorn이라는 속성을 가지고 있지만 동시에 me변수의 name속성도 가지고 있으므로, 같은 속성을 가지고 있기 때문에 me변수에 son을 할당하는것은 가능하다.

  • 하지만 하나의 속성이 부족한 me변수를 son변수에 할당 하는것은 에러를 발생시킨다.

  • 이를 해결하기 위해서는 me변수에 같은 isBorn속성을 추가하거나 isBorn속성을 옵셔널 처리(?)해주면 에러가 해결된다.

type Me = {
  lastName: string;
}

interface Son {
  laseName: sting;
  isBorn: boolean;
}

let me: Me = {
  lastName: 'Lee';
}

let son: Son = {
  lastName: 'Lee';
  isBorn: false;
}

me = son;

son = me; // me변수에는 son변수에 있는 isBorn속성이 존재하지 않으므로 에러가 발생한다.

함수 타입의 호환

  • 위의 객체 타입의 호환과 비슷하게 함수의 타입 호환의 경우는 선언 종류와는 관계없이 파라미터가 같은지를 확인한다.

  • 아래 코드와 같이 파라미터의 갯수를 보면 getNum함수는 1개이고, sum함수는 2개이다.

  • sum함수에 getNum을 할당하게 되면 에러가 발생하지 않지만 1개의 파라미터를 필요로 하는 getNum함수에 sum함수를 할당하게 되면 에러가 발생하다.

function getNum(a) {
  ...
} 
  
const sum = function(x, y) {
  ... 
}
  
getNum = sum  // 에러 발생
sum = getNum // 에러가 발생하지 않는다.

이넘 타입의 호환

숫자형 이넘과 호환되는 number타입

  • 숫자 타입의 a변수를 선언하고 초깃값으로 10을 할당한 후 Language 이넘의 첫 번째 속성 JaveScipt를 할당하면 에러는 발생하지 않는다.
enum Language {
  JavaScript, // 0
  TypeScript  // 1
}

let a: number = 10;
a = Language.JavaScript

이넘 타입 간 호환 여부

  • 위의 객체타입의 구조적 타이핑과 달리 같은 구조를 가진 이넘끼리라고 해도 할당을 하게되면 에러가 발생한다.

제네릭 타입의 호환

  • 제네릭으로 받은 타입이 해당 타입 구조에서 사용되었는지에 따라 결정된다.

  • 값이 할당되어있지 않은 변수끼리는 서로 호환이 가능하다.

interface Empty<T> {

}

let empty1: Empty<sring> = '';
let empty2: Empty<sring> = 99;

empty1 = empty2
empty2 = empty1
  • 하지만 제네릭으로 받은 값이 인터페이스안에서 사용하였다면 구조적으로 타입이 달라지기 때문에 에러가 발생하게 된다.
interface NotEmpty<T> {
  data: T
}

let notEmpty1: NotEmpty<sring>;
let notEmpty2: NotEmpty<sring>;

notEmpty1 = notEmpty2
notEmpty2 = notEmpty1

출처: 쉽게 시작하는 타입스크립트

profile
지속 가능한 성장 습관을 만들어 나가고 싶어요!

0개의 댓글