Type Compatibility

Happhee·2022년 4월 25일
2

📘 TypeScript

목록 보기
8/10

✨ 타입 호환

타입스크립트 코드에서 특정 타입이 다른 타입에 호환되는지의 여부를 판단하는 것이다.

👇 예제 코드를 보자.

interface IGroup {
    name: string;
}
class Dancer {
    constructor(
        name: string,
        age: number
  ) {}
}
let happhee: IGroup;
happhee = new Dancer();

Dancer의 클래스가 명시적으로 IGroup 인터페이스를 상속받지 않지는 않았지만, 타입스크립트에서 이것이 정상적으로 작동하는 이유는 코드의 구조 관점에서 타입이 지정되기 때문이다.

  • ✅ 변수의 구조적 타이핑
let happhee: IGroup;
/* let ive: {
    name: string;
    title: string;
}*/
let ive = { name: "IVE", title: "LOVE DIVE" }
happhee = ive;

ive가 happhee에 호환될 수 있는 이유는 name이라는 속성이 존재하기 때문이다.

  • ✅ 함수 호출의 구조적 타이핑
function pratice(group: IGroup) {
    console.log(`My name is ${group.name}`);
}
pratice(ive);
// ive 타입은 { name: "IVE", title: "LOVE DIVE" }

ive라는 변수에 name 뿐만 아니라 title이라는 속성까지도 존재하기에 asseble 함수의 호출인자로 넘길 수 있다.

Soundness

타입스크립트에서 컴파일 시점에 타입을 추론할 수 없는 타입에 대해서는 일단 안전하다고 넘어가는 특징을 말한다.


❗️ 주의해야 하는 부분 ❗️

Enum

enum 타입은 number 타입과 호환되지만 enum 타입끼리의 호환은 일어날 수 없다.

enum Song { LoveDive, Darling };
enum Fruit { Orange, Strawberry, Apple };

let dance = Song.Darling;

dance = Fruit.Strawberry;
// 'Fruit.Strawberry' 형식은 'Song' 형식에 할당할 수 없습니다.ts(2322)

dance = 2;

dance에는 현재 Song.Darling (1)이 할당되었다. 여기서 다른 enum 타입인 Fruit.Strawberry를 할당하려고 하면 타입 오류가 발생하지만, number 타입의 숫자를 할당은 정상적으로 작동한다.

Class

클래스 타입끼리의 비교에서는 static member와 constructor를 제외한 속성만을 비교한다.

  • ✅ 속성이 같은 경우
class Fruit{
    info: string;
    constructor(color: string, size: string) {
        this.info = color;
    }
}
class Vegetable {
    info: string;
    constructor(size: string) {
        this.info = size;
    }
}
let apple= new Fruit("red", "mideum");
let paprika = new Vegetable("small");

paprika = apple;

console.log(apple, paprika)
// Fruit { info: 'red' } Fruit { info: 'red' }

class Fruit, Vegetable은 속성은 같지만, 생성자가 다르기 때문에 각각에 대한 변수를 생성하고 값을 교환하는 것이 가능하다.

  • ✅ 속성이 다른 경우
class Fruit{
    info: string;
    constructor(color: string, size: string) {
        this.info = color;
    }
}
class Vegetable {
    info: string;
    color: string;
    constructor(size: string) {
        this.info = size;
        this.color = "green";
    }
}
let apple= new Fruit("red", "mideum");
let paprika = new Vegetable("small");

paprika = apple;

console.log(apple, paprika)
// 'color' 속성이 'Fruit' 형식에 없지만 'Vegetable' 형식에서 필수입니다.

앞선 예제 코드에서 class Vegetable에 속성이 color를 추가해보았다.
이렇게 된다면 두 개의 클래스는 타입 호환이 불가능하게 된다.

  • ✅ static member의 경우
class Fruit{
    info: string;
    constructor(color: string, size: string) {
        this.info = color;
    }
}
class Vegetable {
    info: string;
    static color: string;

    constructor(size: string) {
        this.info = size;
    }
}
let apple= new Fruit("red", "mideum");
let paprika = new Vegetable("small");

paprika = apple;

console.log(apple, paprika)

class Vegetable의 속성 color를 static member로 변경하면, 이는 타입 호환에서 제외되므로 오류를 발생시키지 않는다.

Generics

제네릭 타입 간의 호환 여부는 타입 인자 < T >가 속성에 할당되었는 지로 판단한다.

  • ✅ 속성이 없는 경우
interface EmptyFruit<T> {
}
let strawberry: EmptyFruit<number> = {};
let orange: EmptyFruit<string> = {};

strawberry = orange;  

EmptyFruit에서는 member변수인 속성이 존재하지 않기에 strawberry와 orange를 같은 타입으로 여긴다.

  • ✅ 속성이 있는 경우
interface EmptyFruit<T> {
    data: T;
}
let strawberry: EmptyFruit<number> = { data : 12};
let orange: EmptyFruit<string> = {  data : "상큼해"};

strawberry = orange;  
// EmptyFruit<string>' 형식은 'EmptyFruit<number>' 형식에 할당할 수 없습니다.
//  'string' 형식은 'number' 형식에 할당할 수 없습니다.ts(2322)

하지만, 속성 data를 추가하는 경우 제네릭 타입 < T >를 구분하여 타입 호환을 불가능하게 만든다.


📚 학습할 때, 참고한 자료 📚

profile
즐기면서 정확하게 나아가는 웹프론트엔드 개발자 https://happhee-dev.tistory.com/ 로 이전하였습니다

0개의 댓글