본문 바로가기
javascript

number 와 bigint에 관하여 (feat. nestjs)

by cactuslog 2024. 3. 14.
 

BigInt는 ECMAScript2020(ES11)에 추가된 새로운 타입이다.

 

BigInt  Number 타입으로 표현할 수 없는 매우 큰 정수를 다룰 수 있다.

 


 

먼저 Number에 대해 알아보자

 

1. Number는 32 또는 -3.25와 같은 부동소숫점 숫자를 나타낸다.

 

2. 자바스크립트 코드 내에서 255와 같은 숫자 리터럴은 정수가 아닌 부동소수점 값이다.

255 === 255.0 // true

 

3. 자바스크립트의 Number 타입은 Java나 C#의 double과 같은 64비트 이중 정밀도 바이너리 형식 IEEE 754 값이다.

 

4. 이는 분수 값을 나타낼 수 있음을 의미하지만, 저장된 숫자의 크기와 정밀도에는 일정한 제한이 있다.

 

5. 소숫점 이하 17자리 정도만 유지하며 나머지는 반올림한다.

 

6. Number가 표현할 수 있는 정수의 범위는 다음과 같다.

Number.MIN_SAFE_INTEGER //-9007199254740991

Number.MAX_SAFE_INTEGER //9007199254740991

 

 

 

Number 함수

 

1. Number(value)처럼 함수로 사용하면 문자열이나 다른 값을 Number 타입으로 변환한다.

 

2. 변환할 수 없으면 NaN을 리턴 한다

 

3. 빈 문자열은 아무것도 없음으로 간주되어 0을 반환한다.

 

4. null은 의도적인 부재를 나타내며 이 또한 0을 반환한다.

Number("123") === 123; // true
Number("123.00"); // 123

Number("hello"); // NaN
Number(undefined); // NaN

Number(null); // 0
Number(""); // 0

 


 

BigInt

 

1. Number가 나타낼 수 있는 최대치인 2^53-1(16자리)보다 큰 정수를 표현할 수 있다.

 

2. 정수 리터럴 뒤에 n을 붙이거나 함수 BigInt를 호출해서 생성할 수 있다.

const theBiggestInt = 9007199254740991n;

const alsoHuge = BigInt(9007199254740991);
// 9007199254740991n

const hugeString = BigInt("9007199254740991");
// 9007199254740991n

 

 

3. BigInt는 내장 Math 객체의 메서드와 함께 사용할 수 없다.

 

4. 또한 Number와 혼합해서 연산할 수 없다.

1n === 1 // false

1n + 2;
//Uncaught TypeError: Cannot mix BigInt and other types

 

5. 비교의 경우 Number와 같이 사용할 수 있다. ( '=== '제외 )

 

6. BigInt는 / 연산에서 소숫점 이하를 버린다.

const expected = 4n / 2n;
// 2n

const rounded = 5n / 2n;
// 2n

 

 

7. BigInt Number로 변환하는 과정에서 정확도를 유실할 수 있으므로, 2^53보다 큰 값을 예상할 수 있는 경우 BigInt만 사용하는 것을 권장한다.

 


 

BigInt 직렬화

 

1. 사실 이 주제를 위해 위의 내용을 빌드업했다.

 

2. express, nestjs 등 자바스크립트 기반 서버에서 JSON으로 return 할 경우 문제가 발생한다.

 

3. BigInt직렬화할 수 없기 때문에, JSON.stringify() BigInt를 포함한 값을 전달한다면 TypeError가 발생한다.

 

4. 따라서 최상단에 toJSON을 정의해 주어야한다.

BigInt.prototype['toJSON'] = function () {
  return this.toString();
};

 

 


 

nestjs에서 직렬화 테스트

 

반환 타입

@ObjectType()
export class TestOutput {
  @Field(() => GraphQLBigInt)
  id: bigint;
}

 

resolver

@Query(() => TestOutput)
test() {
  return this.keywordService.test();
}

 

service

@Injectable()
export class KeywordService {  
  test() {
    return { id: 9012324124214212121122455n };
  }
}

 

 

1. 먼저 Number로 표현 불가한 bigint를 반환하자.

 

2. 문자열로 직렬화된 결과를 볼 수 있다.

{
  "data": {
    "test": {
      "id": "9012324124214212121122455"
    }
  }
}
 

 

3. Number로 표현 가능한 bigint를 반환하면 Number로 반환한다.

@Injectable()
export class KeywordService {  
  test() {
    return { id: 9012324n };
  }
}
{
  "data": {
    "test": {
      "id": 9012324
    }
  }
}

 

 

문자열로 직렬화된 id를 다시 bigint로 변경해서 사용하는 것을 잊지 말자!

const id = BigInt("9007199254740991");
// 9007199254740991n