[typescript] const, as const, readonly ??

pudding·2023년 1월 19일
4
post-thumbnail

몇 달 전 강의를 보는데 아래와 같은 코드를 보았다.

const a = something as const;

그 당시 typescript 라곤 type 정의 정도만 했기 때문에 const 키워드를 썼는데 뒤에 as const 는 뭐하는 녀석인지 몰랐다. 그래서 강의를 멈추고 바로 구글링했다. 지금 글은 내가 알고 있는 대로 작성할 예정이다. 그런데 개발하다가 아니 유튜브를 보다가도 갑자기 뭔가 궁금해지면 하던거 멈추고 바로 구글링 하는거 나만 이런가? 궁금증 못 참는 성격..

📕 const

몇 년 전 const 변수가 값이 바뀐다는 소리를 듣고 정말 깜짝 놀랐다. 그 당시 const 선언한 변수는 변하지 않는다고만 굳게 믿고 있었는데.
아래는 MDN 공식문서의 const에 대한 설명이다.

The value of a constant can't be changed through reassignment (i.e. by using the assignment operator), and it can't be redeclared (i.e. through a variable declaration). However, if a constant is an object or array its properties or items can be updated or removed.

상수값은 재할당을 통해 바뀔수 없으며, 재선언이 될 수 없다. 그러나 만약 상수가 object 이거나 array 라면 그것의 properties 나 items 들은 수정되거나 지워질 수 있다... 그러니까 간단히 말해서 메모리 주소 값만 고정이라는거지? 그렇다면 아래처럼 될 수 있다는 말이다.

const obj = {
	name: 'pudding',
    age: 30
};
const array = [1, 2, 3];

obj.age = 20; // fine
array.push(4); // fine

📕 as const

그럼 property 값이 변하지 않도록 할 수는 없을까? 이에 대한 해답이 typescript 의 "as const" 이다.

const obj = {
	name: 'pudding',
    age: 30
} as const;
const array = [1, 2, 3] as const;

obj.age = 20; // error
array.push(4); // error

이제 우리가 원하는 결과가 나왔다. 그런데 더 심오한 내용도 있다. 아래 코드를 보자.

const numbers1 = [1, 2];
const numbers2 = [1, 2] as const;

const plus = (a: number, b: number) => {
	return a + b;
}

console.log(plus(...numbers1)); // error
console.log(plus(...numbers2)); // fine

같은 값인데 하나는 에러가 나고 하나는 잘 동작한다. 이유는 타입에 있다.
numbers1과 numbers2 둘의 타입이 어떻게 다른지 보자.

numbers1: number[] numbers2: readonly [1, 2]
numbers1의 타입은 number[], numbers2의 타입은 readonly [1, 2] 이다. plus 함수는 매개변수 두개만을 갖는다. 그래서 number[] 타입인 numbers1 을 넘겨주려고 하면 에러가 나는 것이다. number array 사이즈를 모르니까! 반면에 numbers2의 타입은 readonly [1, 2] 로 고정되어 있다. as const를 선언함으로써 값이 변하지 않는다는 것을 알았으니 plus 함수는 numbers2를 매개변수로 받을 수 있다.

📕 readonly

as const 는 속성과 변수의 타입을 고정시키는 용도고, readonly 는 변수가 아닌 class, interface, type 등의 속성을 위한 것이다. 아래 예제를 보자.

class A {
  obj1 = { property: 123 } as const;
  // A.obj1: { readonly propery: 123 };
  readonly obj2 = { property: 123 };
  // A.obj2: { propery: number };
  readonly obj3 = { property: 123 } as const;
  // A.obj3: { readonly propery: 123 };

  setObj() {
    this.obj1 = { property: 123 }; // fine
    this.obj2 = { property: 123 }; // error
    this.obj3 = { property: 123 }; // error
  }

  setObjPropery() {
    this.obj1.property = 123; // error
    this.obj2.property = 123; // fine
    this.obj3.property = 123; // error
  }
}

object 에 as const 를 사용하면 typescript 에서 속성들을 readonly 로 추론한다. 그러므로 A.obj1 의 타입은 { readonly property: 123 } 으로 A.obj1에 같은 타입인 { property: 123 } 로 재할당은 가능하다. 하지만 object 안의 속성 값은 readonly 이기 때문에 수정이 불가능하다. obj2의 타입은 { property: number } 으로 추론된다. 하지만 obj2 자체가 readonly 이기 때문에 값을 다시 할당하려고 하면 에러가 나지만 안의 속성값은 readonly 가 아니므로 수정이 가능하다. readonly 와 as const 두개의 키워드를 사용하면 당연히 두개 다 불가능하다.

💡 결론

  • const 키워드는 재할당이 불가능할 뿐 object의 property 값이나, array 의 아이템들은 수정이 될 수 있다.
  • readonly도 const 와 마찬가지로 변수나 속성 앞에 붙힌다고 해서 object나 array 안의 값들이 수정이 안되는 게 아님.
  • const는 변수, readonly는 속성에 쓰임.
  • as const 키워드를 사용하면 object의 property 값이나, array 의 아이템들은 수정 불가능하다. 하지만 constant variable이나 readonly property이 아니면 같은 타입으로 재할당 가능하다.

나름 쉽게 풀어쓰려고 했는데 작문 능력이 많이 부족하다는 걸 깨달았다. 뭐 많이 쓰다보면 늘겠지😂 이어서 literal type 에 대한 내용까지 작성하려다 글이 너무 길어지고 이제 시작하는 분들에겐 이정도만으로도 충분하다고 생각했다. 나중에 정리하기로 하며 이만 마친다.

profile
I don't wanna be one of them.

0개의 댓글