TS - Symbol

00_8_3·2023년 5월 13일
0

typescript

목록 보기
8/8

Symbol vs Symbol.for

symbol

Symbol은 JS의 원시타입 중 하나로

고유함을 보장하는 값을 나타낸다.

const a = Symbol("a")
const b = Symbol("a")

console.log(a === b) // false

Symbol로 같은 키값으로 생성한다고 해도 늘 고유한 값을 생성하기 때문에
위 비교에서 false가 나온다.

symbol.for

const a = Symbol.for("a")
const b = Symbol.for("a")

console.log(a === b) // true

symbol.for는 전역 symbol 레지스트리에 저장이된다.

js 런타임 내의 전역을 말한다.

전역에 없으면 새로 생성하고
있으면 기존의 symbol을 호출한다.

그래서 위 비교에서 true이다.

서로 다른 symbol

const a = Symbol("a")
const b = Symbol.for("a")

console.log(a === b) // false

Symbol과 Symbol.for 둘다 Symbol을 생성하니깐
위 코드가 서로 같다고 생각 할 수 있지만

Symbol.for는 Symbol.for로 생성된 Symbol만 비교가 가능하기 때문에

false가 나온다.

unique symbol

unique symbol은 타입스크립트 2.7에서 소개된 타입이다.

unique symbol 타입은 symbol의 서브타입으로
Symbol 또는 Symbol.for로 생성되는 경우 또는 직접적으로 타입 명시된 경우에만 선언된다.
또한 const에만 명시 가능하다.

symbol.for와 unique symbol

위에서 symbol.for의 경우 기존에 존재하면 그것을 가져온다고 했다.

const b: unique symbol = Symbol.for("a");
const c: unique symbol = Symbol.for("a");

console.log( b === c );

JS 런타임에서는 같은 전역 심볼을 가르켜 문제가 없지만

컴파일 타임에서는 unique symbol 타입을 갖는 경우에는 서로 같은 symbol을 갖는다고 해도

고유한 symbol로 보기 때문에 에러 밑줄을 보게 된다.

타입 시스템 차원에서 심볼이 고유하다는 것을 나타내주어
조금 더 안전하고 예측가능한 코드 작성에 도움을 준다.

안전한 코드 보장

const MESSAGE_TYPE = Symbol();
// const MESSAGE_TYPE: unique symbol = Symbol(); // 타입 생략가능.

const Test= Symbol();

interface Message {
  type: typeof MESSAGE_TYPE;
  payload: string;
}

let message: Message = {
  type: MESSAGE_TYPE,
  payload: "Hello, world!",
};

let message2: Message = {
  type: TEST, // 컴파일 타임 에러.
  payload: "Hello, world!",
};

console.log(message.type === MESSAGE_TYPE); // true

console.log(message.type === TEST); // 컴파일 타임 에러.

위와 같은 경우 의도치 않는 속성의 접근이나 수정을 컴파일 타임에서 방지할 수 있다.

Nest와 Symbol 살펴보기

Nest code를 살펴보면

symbol과 symbol.for을 둘 다 아래와 같은 형태로 사용 중이다.

export const aa = Symbol("test");

export const bb = Symbol.for("test1");

Symbol의 경우 export const SYMBOL_TOKEN = Symbol('token'); 와 같이 같은 key 이름으로 여러 모듈에서 선언되어 있고
같은 디렉토리의 다른 모듈에서 호출해서 사용한다.

https://github.com/nestjs/nest/blob/master/integration/inspector/src/properties/properties.service.ts#L4
https://github.com/nestjs/nest/blob/master/integration/injector/src/properties/properties.service.ts#L4

Symbol.for의 경우 export를 사용해 선언이 되지만 선언된 모듈에서만 사용된다.

https://github.com/nestjs/nest/blob/master/packages/core/helpers/handler-metadata-storage.ts#L9
https://github.com/nestjs/nest/blob/master/packages/core/injector/instance-wrapper.ts#L21...L22

모듈 캐쉬 삭제

require.cache를 사용하여 모듈의 캐쉬를 지우게 되면

Symbol의 경우 모듈이 리로드 되면서 기존의 Symbol과 다른 Symbol이 생성이 된다.

Symbol.for의 경우는 전역 레지스트리에 저장되어 있기 때문에 캐쉬를 초기화 해도 똑같다.

require.cache를 호출해서 삭제하는 경우는 별로 없겠지만
symbol 사용할 때는 조심하자.

의문

  1. Symbol는 같은 키로 선언되어도 유니크한데 같은 변수이름으로 선언해서 사용하면
    import 해서 사용할 때 헷갈리지 않나?

  2. Symbol.for의 경우 굳이 export 하지 않아도 다른 모듈에서 호출해서 사용 할수 있기도 하고
    export 했으면 다른 모듈에서 사용되야 할텐데 그렇지 않다. 왜?

참고

https://www.typescriptlang.org/docs/handbook/symbols.html

0개의 댓글