오늘은 세팅을 진행하였다.
폴더안에는 메서드와 그에 대한 테스트 코드로 이루어져 있다.

일단 간단하게 테스트 코드 용어부터 정리해보자
vitest 테스트 코드 실행 시 컬럼 의미
| % Stmts | 전체 statement(구문) 중 테스트된 비율 |
| % Branch | if, switch 등 분기(branch) 중 테스트된 비율 |
| % Funcs | 함수 중 테스트된 비율 |
| % Lines | 전체 코드 줄 중 테스트된 비율 |
| Uncovered Line #s | 테스트되지 않은 라인 번호 목록 |
그후 눈에 뛰는 메서드 하나를 나는 분석해 보았다.
생각보다 본 함수는 심플하다
import { toFinite } from './toFinite.ts';
/**
* Converts `value` to an integer.
*
* This function first converts `value` to a finite number. If the result has any decimal places,
* they are removed by rounding down to the nearest whole number.
*
* @param {unknown} value - The value to convert.
* @returns {number} Returns the number.
*
* @example
* toInteger(3.2); // => 3
* toInteger(Number.MIN_VALUE); // => 0
* toInteger(Infinity); // => 1.7976931348623157e+308
* toInteger('3.2'); // => 3
* toInteger(Symbol.iterator); // => 0
* toInteger(NaN); // => 0
*/
export function toInteger(value: any): number {
const finite = toFinite(value);
const remainder = finite % 1;
return remainder ? finite - remainder : finite;
}
유한수로 바꾼 뒤 소수일 경우에 소수점을 제거하는 로직인 것 같다.
한 뎁스 더 이동해보자
import { toNumber } from './toNumber.ts';
/**
* Converts `value` to a finite number.
*
* @param {unknown} value - The value to convert.
* @returns {number} Returns the number.
*
* @example
* toFinite(3.2); // => 3.2
* toFinite(Number.MIN_VALUE); // => 5e-324
* toFinite(Infinity); // => 1.7976931348623157e+308
* toFinite('3.2'); // => 3.2
* toFinite(Symbol.iterator); // => 0
* toFinite(NaN); // => 0
*/
export function toFinite(value: any): number {
if (!value) {
return value === 0 ? value : 0;
}
value = toNumber(value);
if (value === Infinity || value === -Infinity) {
const sign = value < 0 ? -1 : 1;
return sign * Number.MAX_VALUE;
}
return value === value ? (value as number) : 0;
}
1. falsy 한 값 NaN, false, [], null, undefined에 대해 0을 반환한다.
2. 숫자로 변경한다.
3. 무한수에 대해서는 가장 큰 유한 수로 바꾼다.
4. return value === value ? (value as number) : 0; NaN에 대해서는 false를 반환한다.
그렇다면 isNaN 메서드를 쓰지 않은 이유가 무엇일까?
기존 isNaN 문제점
1. isNaN('abc') -> true를 반환한다. (문자열일 경우 정확하지 않음)
Number.isNaN(NaN) // true
Number.isNaN("abc") // false
2. 내부적으로 타입 체크 + 비교 두 번 하므로 핫 패스(핵심 반복 로직)에 넣기에는 상대적으로 느리다.
한 뎁스 더 이동해보자
import { isSymbol } from '../predicate/isSymbol.ts';
/**
* Converts `value` to a number.
*
* Unlike `Number()`, this function returns `NaN` for symbols.
*
* @param {unknown} value - The value to convert.
* @returns {number} Returns the number.
*
* @example
* toNumber(3.2); // => 3.2
* toNumber(Number.MIN_VALUE); // => 5e-324
* toNumber(Infinity); // => Infinity
* toNumber('3.2'); // => 3.2
* toNumber(Symbol.iterator); // => NaN
* toNumber(NaN); // => NaN
*/
export function toNumber(value: any): number {
if (isSymbol(value)) {
return NaN;
}
return Number(value);
}
JavaScript는 숫자 변환 실패 = NaN이라는 규칙을 갖고 있고 위의 조건 때문에 다음과 같이 심볼의 경우 NaN을 반환하는 것 같다.
그냥 js 메서드인 number로 심볼을 변환하면 오류와 함께 어떠한 값도 반환하지 않는다.
/**
* Check whether a value is a symbol.
*
* This function can also serve as a type predicate in TypeScript, narrowing the type of the argument to `symbol`.
*
* @param {unknown} value The value to check.
* @returns {value is symbol} Returns `true` if `value` is a symbol, else `false`.
* @example
* isSymbol(Symbol.iterator);
* // => true
*
* isSymbol('abc');
* // => false
*/
export function isSymbol(value: any): value is symbol {
return typeof value === 'symbol' || value instanceof Symbol;
}
isSymbol(v) 가 true면
if 블록 안에서 v는 symbol 타입으로 확정됨.
아래와 같은 심볼이 object인 경우에 판단이 안되기 때문에 이렇게 함수를 만든 것 같다.
typeof Object(Symbol("abc")) // "object"
자 어느정도 살펴보았으니 하이라이트인 테스트 코드를 살펴보자
양이 꽤 되서 내가 이해가 안되는 부분 위주로 가져와 보았다.
describe('toInteger', () => {
it(`should preserve the sign of \`0\``, () => {
const values = [0, '0', -0, '-0'];
const expected = [
[0, Infinity],
[0, Infinity],
[-0, -Infinity],
[-0, -Infinity],
];
[0, 1].forEach(index => {
const others = values.map(index ? Object : identity);
const actual = others.map(value => {
const result = toInteger(value);
return [result, 1 / result];
});
expect(actual).toEqual(expected);
});
});
toInteger(value)가 “+0”과 “–0”을 정확하게 구분해서 반환하는지 확인하는 테스트가 포함되어 있다.
오늘 느낀점
생각보다 메서드 자체의 이해가 그렇게 어렵지는 않은 것 같은데
예외 케이스에 대한 고민들이 정말 많이 느껴졌다..
테스트 커버리지가 적은 부분에서 찾아보면 좋을 것 같다.
'es-toolkit' 카테고리의 다른 글
| [es-toolkit] 기여 도전하기 2일차 (0) | 2025.11.28 |
|---|