타입스크립트의 타입 호환, 타입의 구조적 호환성(+함수, 제네릭, 이넘)

boyeonJ·2023년 8월 23일
0

TypeScript

목록 보기
11/12
post-thumbnail

타입호환이란?

타입스크립트(TypeScript)의 "타입 호환성"은 두 가지 타입 간에 값이 할당 가능한지 여부를 나타내는 개념입니다. 즉, 어떤 타입의 값이 다른 타입으로 변환되거나 할당될 수 있는지를 판단하는 규칙의 모음입니다. 이를 통해 코드 작성 시 불필요한 오류를 방지하고 타입 안정성을 유지할 수 있습니다.

타입스크립트의 타입 호환성은 4가지로 나누어서 이해할 수 있습니다.

1. 타입의 구조적 호환성 (Structural Compatibility)

타입의 구조적 형태가 얼마나 유사한지를 고려합니다. 즉, 타입유형(type, interface..)이 아닌 타입의 구조(같은 속성과 타입인지)를 통해 호환 유무를 판단합니다. 이를 통해 타입 간에 불필요한 제약 없이 유연한 코드 작성이 가능합니다.

// 인터페이스 A와 B 정의
interface A {
  x: number;
}

interface B {
  x: number;
  y: number;
}

// A는 B로 할당 가능합니다. (넘치는건 가능)
let a: A = { x: 1 };
let b: B = a; // 가능

// B는 A로 할당 불가능합니다. (부족한건 불가능)
let bb: B = { x: 1, y: 2 };
let aa: A = bb; // 오류! Property 'y'가 필요합니다.

2. 함수 타입의 호환성

함수의 역시 구조적 타이핑 관정에서 함수 구조가 유사하면 호환이 가능합니다. 매개변수와 반환 타입이 다른 함수의 동작을 보장해 줄 수 있다면 해당 함수는 호환이 가능합니다.

type FuncA = (x: number) => number;
type FuncB = (x: number, y: number) => number;

// FuncA는 FuncB로 할당 가능합니다. (매개변수가 적어지는건 가능)
let fnA: FuncA = (x) => x * 2;
let fnB: FuncB = fnA; // 가능

// FuncB는 FuncA로 할당 불가능합니다.  (매개변수가 많아지는건 불가능)
let fnBB: FuncB = (x, y) => x + y;
let fnAA: FuncA = fnBB; // 오류! 불필요한 매개변수 'y'가 있습니다.

3. 이넘의 호환성

타입스크립트의 이넘은 직접 값을 할당해주지 않으면 숫자값이 지정이 됩니다. 이러한 숫자형 이넘은 number type과 호환됩니다.

// 이넘의 호환성 예시
enum Direction {
  Up, //0
  Down, //1
  Left, //2
  Right, //3
}

let directionValue: Direction;
directionValue = Direction.Up; // 가능
directionValue = 1; // 가능, 숫자 값 할당도 가능

let anotherDirection: Direction;
anotherDirection = "Left"; // 오류! 문자열은 이넘과 호환되지 않습니다.

이넘은 이넘타입간은 호환이 불가능합니다. 따라서 이넘은 구조적 타이핑개념이 적용 되지 않습니다.

enum Color {
  Red,
  Green,
  Blue,
}
enum Shape {
  Circle,
  Square,
  Triangle,
}
let colorValue: Color = Color.Red;
let shapeValue: Shape = Shape.Circle;
colorValue = shapeValue; // 오류! 이넘 타입 간 호환 불가능

4. 제네릭의 호환성

제네릭은 받은 타입을 통해 일반적인 타입호환과 같게 동작합니다. 하지만 만약 받은 타입이 해당 구조에서 사용되지 않는다면 타입호환의 영향을 주지 않습니다.

// 제네릭의 호환성 예시
interface Box<T> {
  value: T;
}

let box1: Box<number>;
let box2: Box<string>;

box1 = box2; // 오류! 제네릭의 타입이 다르기 때문에 호환되지 않습니다.

// 하지만 제네릭 타입이 실제로 사용되는 경우에는 호환됩니다.
let numBox: Box<number>;
let anyBox: Box<any>;

numBox = anyBox; // 가능, 'any' 타입은 모든 타입과 호환됩니다.

0개의 댓글