본문 바로가기

Typescript

const assertions 이해하기

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions

 

TypeScript를 쓰다 보면 객체나 배열 뒤에 붙은 as const를 종종 보게 된다. 처음 봤을 때는 “그냥 const로 선언했는데 또 as const는 뭐지?” 하는 의문이 들었다. 나 역시 이 키워드가 정확히 어떤 역할을 하는지 몰랐고, 그냥 붙이는 습관처럼 사용하곤 했다. 하지만 알고 나면, as const는 타입 안정성을 높이는 데 매우 강력한 도구다.

 

문제 상황

 

다음 코드를 보자.

const NodeType = {
  GROUP: "Groups",
  TABLE: "Table",
};

 

겉보기엔 단순한 상수 객체처럼 보이지만, TypeScript는 내부 값을 다음처럼 해석한다.

type NodeType = {
  GROUP: string;
  TABLE: string;
};

 

즉 "Groups"와 "Table"이라는 리터럴 타입이 아니라, 단순히 string으로 추론되는 것이다. 이 말은 다음 코드가 타입 에러 없이 통과된다는 뜻이다.

NodeType.GROUP = "SomethingElse"; // 타입상 가능하다

 

as const를 붙이면 무슨 일이 일어날까?

 

이제 위 코드를 이렇게 바꿔보자.

const NodeType = {
  GROUP: "Groups",
  TABLE: "Table",
} as const;

이 한 줄이 추가된 순간, 타입스크립트는 완전히 다르게 해석한다.

type NodeType = {
  readonly GROUP: "Groups";
  readonly TABLE: "Table";
};

 

즉, as const를 붙이면 다음 세 가지 일이 일어난다.

1. 모든 프로퍼티가 readonly로 바뀐다. → 더 이상 재할당할 수 없다.

2. 값이 리터럴 타입으로 고정된다. → "Groups"는 단순 string이 아니라 "Groups" 그 자체의 타입이 된다.

 

왜 중요한가?

 

이제 아래와 같은 코드를 보면 as const의 진가가 드러난다.

const NodeType = {
  GROUP: "Groups",
  GROUP_NET: "GroupNet",
  TABLE: "Table",
  FILTER: "Filter",
  UNION: "Union",
} as const;

type NodeTypeValue = typeof NodeType[keyof typeof NodeType];

 

이때 NodeTypeValue는 다음과 같은 타입이 된다.

"Groups" | "GroupNet" | "Table" | "Filter" | "Union"

 

즉, 객체의 value들을 자동으로 유니온 타입으로 추출할 수 있게 된다. 만약 as const가 없었다면? 그냥 string으로만 인식돼서 이런 타입 추론이 불가능하다.

 

배열에서도 동일하게 동작한다.

 

as const는 객체뿐 아니라 배열에도 사용할 수 있다.

const colors = ["red", "blue", "green"] as const;

 

이 경우 TypeScript는 다음처럼 추론한다.

readonly ["red", "blue", "green"];