본문 바로가기
카테고리 없음

TypeScript 25강: 리터럴 타입과 튜플(Tuple)의 효과적인 사용법

by mystory55776 2025. 5. 25.

리터럴 타입(Literal Type)이란?

TypeScript 리터럴 타입은 특정한 값만을 허용하는 타입으로, string, number, boolean의 구체적인 값을 타입으로 지정할 수 있습니다. 예를 들어, 문자열 `"yes"`만 허용하거나 숫자 1만 허용하는 타입을 만들 수 있습니다.

let answer: "yes" | "no";
answer = "yes"; // OK
answer = "no";  // OK
// answer = "maybe"; // Error: '"maybe"'는 허용되지 않음

리터럴 타입은 함수나 객체의 입력 값을 정확하게 제한하고자 할 때 유용합니다.

리터럴 타입과 유니온 타입 결합

리터럴 타입은 유니온 타입과 함께 사용하면, 허용 가능한 값의 범위를 명확히 지정할 수 있습니다.

type Direction = "up" | "down" | "left" | "right";

function move(dir: Direction) {
  console.log(`Moving ${dir}`);
}

move("up");    // OK
move("left");  // OK
// move("back"); // Error

이처럼 Direction 타입은 제한된 문자열 값만을 허용하여 오타나 잘못된 입력을 방지할 수 있습니다.

리터럴 타입을 활용한 타입 좁히기

TypeScript에서는 리터럴 타입을 이용해 타입 좁히기(Type Narrowing)를 할 수 있으며, 조건문과 함께 사용하면 안전한 분기 처리가 가능합니다.

function getIcon(type: "info" | "warning" | "error") {
  if (type === "info") {
    return "ℹ️";
  } else if (type === "warning") {
    return "⚠️";
  } else {
    return "❌";
  }
}

이 방식은 TypeScript가 각 분기 내에서 타입을 자동으로 좁혀주기 때문에, 런타임 오류를 줄이고 안전한 코드를 작성할 수 있게 도와줍니다.

튜플(Tuple)이란 무엇인가?

TypeScript 튜플(Tuple)은 고정된 수의 요소를 가지는 배열로, 각 요소의 타입이 지정되어 있습니다. 일반 배열과 달리 요소마다 다른 타입을 지정할 수 있어 구조화된 데이터를 표현하기에 적합합니다.

let userInfo: [string, number];
userInfo = ["Alice", 25];   // OK
// userInfo = [25, "Alice"]; // Error: 순서 및 타입 불일치

튜플은 구조가 명확하고 정해진 위치에 특정 타입의 값이 들어가야 할 때 유용하게 사용됩니다.

튜플의 구조 분해(Destructuring)

튜플은 배열처럼 구조 분해 할당을 사용할 수 있으며, 각 위치의 타입이 고정되어 있어 코드의 명확성과 안정성을 높입니다.

const point: [number, number] = [10, 20];
const [x, y] = point;
console.log(`X: ${x}, Y: ${y}`);

튜플의 각 요소는 명확한 타입을 갖고 있으므로, 변수 xy도 각각 number 타입으로 추론됩니다.

튜플에 리터럴 타입 적용하기

리터럴 타입과 튜플을 함께 사용하면, 더 강력한 타입 제어가 가능합니다. 특히 이벤트, 파라미터 명세, 커맨드 처리 등의 로직에 적합합니다.

type Command = ["start", number] | ["stop", string];

function handleCommand(cmd: Command) {
  if (cmd[0] === "start") {
    console.log(`Starting with ID: ${cmd[1]}`);
  } else {
    console.log(`Stopping: ${cmd[1]}`);
  }
}

handleCommand(["start", 123]); // OK
handleCommand(["stop", "done"]); // OK
// handleCommand(["start", "oops"]); // Error

위 예제는 튜플의 첫 번째 요소로 명령어를, 두 번째 요소로 데이터를 받는 형식을 정해 명확한 데이터 구조를 제공합니다.

튜플의 확장 (Rest 요소)

TypeScript 4.0 이후부터는 튜플에 Rest 요소를 사용할 수 있어, 일부 요소만 고정하고 나머지는 유동적으로 처리할 수 있습니다.

type Log = [string, ...number[]];

const log1: Log = ["데이터", 1, 2, 3];
const log2: Log = ["이벤트"]; // 숫자 없이도 OK

이 기능은 고정된 앞부분과 가변적인 뒷부분을 갖는 데이터 구조에 유용하게 사용됩니다.

실무에서의 활용 사례

  • API 응답에서 고정된 순서의 데이터 처리
  • 상태 전이(state transition) 정의
  • 이벤트 핸들러에서 커맨드 패턴 구현
  • 파라미터의 순서와 타입이 중요한 함수 설계

튜플과 리터럴 타입은 사용자가 정의한 구조를 명확하게 표현하고, 예상치 못한 입력을 방지할 수 있도록 돕습니다.

결론: 정밀한 타입 제어를 위한 리터럴과 튜플의 활용

TypeScript의 리터럴 타입은 값 자체를 타입으로 제한할 수 있는 기능이며, 튜플은 고정된 형태의 데이터를 명확히 표현할 수 있는 타입입니다. 두 기능은 실무에서 데이터 모델을 세밀하게 정의하고, 예측 가능한 코드를 작성하는 데 큰 도움이 됩니다.

정확한 타입 제어가 필요한 상황에서 이 두 가지 기능을 적절히 활용한다면, 코드의 안정성은 물론, 유지보수성과 가독성도 크게 향상될 것입니다.