From b391d169e5af0f4f7044dceab8967b746772805b Mon Sep 17 00:00:00 2001 From: ssi02014 Date: Mon, 13 Jan 2025 04:43:03 +0900 Subject: [PATCH] =?UTF-8?q?fix(utils):=20formatValueWithSymbol=20=EC=9E=90?= =?UTF-8?q?=EC=97=B0=EC=8A=A4=EB=9F=AC=EC=9A=B4=20=EC=97=AD=ED=95=A0=20?= =?UTF-8?q?=EC=9D=B4=ED=95=B4=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/empty-forks-argue.md | 5 + .../formatter/formatNumberWithCurrency.md | 103 ----------- .../utils/formatter/formatValueWithSymbol.md | 67 +++++++ .../formatNumberWithCurrency.constants.ts | 25 --- .../formatNumberWithCurrency.spec.ts | 134 -------------- .../formatNumberWithCurrency.types.ts | 11 -- .../formatNumberWithCurrency.utils.ts | 33 ---- .../formatNumberWithCurrency/index.ts | 173 ------------------ .../formatValueWithSymbol.spec.ts | 74 ++++++++ .../formatValueWithSymbol.types.ts | 5 + .../formatValueWithSymbol.utils.ts | 35 ++++ .../formatter/formatValueWithSymbol/index.ts | 53 ++++++ packages/utils/src/formatter/index.ts | 2 +- 13 files changed, 240 insertions(+), 480 deletions(-) create mode 100644 .changeset/empty-forks-argue.md delete mode 100644 docs/docs/utils/formatter/formatNumberWithCurrency.md create mode 100644 docs/docs/utils/formatter/formatValueWithSymbol.md delete mode 100644 packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.constants.ts delete mode 100644 packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.spec.ts delete mode 100644 packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.types.ts delete mode 100644 packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.utils.ts delete mode 100644 packages/utils/src/formatter/formatNumberWithCurrency/index.ts create mode 100644 packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.spec.ts create mode 100644 packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.types.ts create mode 100644 packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.utils.ts create mode 100644 packages/utils/src/formatter/formatValueWithSymbol/index.ts diff --git a/.changeset/empty-forks-argue.md b/.changeset/empty-forks-argue.md new file mode 100644 index 000000000..8dc417cee --- /dev/null +++ b/.changeset/empty-forks-argue.md @@ -0,0 +1,5 @@ +--- +'@modern-kit/utils': patch +--- + +fix(utils): formatValueWithSymbol 자연스러운 역할 이해를 위해 네이밍 변경 - @ssi02014 diff --git a/docs/docs/utils/formatter/formatNumberWithCurrency.md b/docs/docs/utils/formatter/formatNumberWithCurrency.md deleted file mode 100644 index 2cf3ad607..000000000 --- a/docs/docs/utils/formatter/formatNumberWithCurrency.md +++ /dev/null @@ -1,103 +0,0 @@ -# formatNumberWithCurrency - -`숫자` 혹은 `숫자로 이루어진 문자열`을 주어진 `통화 기호`를 추가하는 함수입니다. - -기본 옵션으로 직접 원하는 형태로 숫자에 통화 기호를 추가해 포맷팅할 수 있습니다. -- 기본 옵션: `symbol`, `position`, `space`, `commas` - -`locale` 옵션이 있으면 `locale` 형식에 따라 포맷팅됩니다. -- `locale` 옵션을 제외한 나머지 옵션들은 무시됩니다. - -
- -## Code -[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/formatter/formatNumberWithCurrency/index.ts) - -## Interface -```ts title="typescript" -interface FormatNumberCurrencyOptions { - symbol?: string; // default: '' - position?: 'prefix' | 'suffix'; // default: 'suffix' - space?: boolean; // default: false - commas?: boolean; // default: true - locale?: Locale; -} -``` -```ts title="typescript" -// 옵션 없이 사용 -function formatNumberWithCurrency(value: number | string): string; - -// locale 옵션을 제외한, 기본 옵션이 주어지면 주어진 옵션에 따라 포맷팅됩니다. -// (기본 옵션: `symbol`, `position`, `space`, `commas`) -function formatNumberWithCurrency( - value: number | string, - options: Omit -): string; - -// locale 옵션이 있으면 locale 형식에 따라 포맷팅됩니다. -function formatNumberWithCurrency( - value: number | string, - options: { locale: Locale } -): string; -``` - -## Usage -### 기본 동작 -```ts title="typescript" -import { formatNumberWithCurrency } from '@modern-kit/utils'; - -// 기본 동작 -formatNumberWithCurrency(1000) // '1,000' -formatNumberWithCurrency(-1000) // '-1,000' -formatNumberWithCurrency(1000.123) // '1,000.123' - -// 숫자로 이루어진 문자열도 허용 -formatNumberWithCurrency('1000') // '1,000' -formatNumberWithCurrency('-1000') // '-1,000' -formatNumberWithCurrency('1000.123') // '1,000.123' -``` - -
- -### 옵션 사용 -- 기본 옵션 사용(`symbol`, `position`, `space`, `commas`) -```ts title="typescript" -import { formatNumberWithCurrency } from '@modern-kit/utils'; - -// 통화 기호 추가 (기본 값: '') -formatNumberWithCurrency(1000, { symbol: '원' }) // '1,000원' - -// 통호 기호 위치 변경 (기본값: 'suffix') -formatNumberWithCurrency(1000, { symbol: '$', position: 'prefix' }) // '$1,000' - -// 공백 추가 (기본값: false) -formatNumberWithCurrency(1000, { symbol: '$', position: 'prefix', space: false }) // '$1000' -formatNumberWithCurrency(1000, { symbol: '$', position: 'prefix', space: true }) // '$ 1000' - -// 천의 단위 구분 여부 (기본값: true) -formatNumberWithCurrency(1000, { symbol: '원', commas: false }) // '1000원' -formatNumberWithCurrency(1000, { symbol: '원', commas: true }) // '1,000원' -``` - -
- -### 옵션 사용2 -- `locale` 옵션 사용 -```ts title="typescript" -import { formatNumberWithCurrency } from '@modern-kit/utils'; - -// locale 옵션이 있으면 locale 형식에 따라 포맷팅됩니다. -formatNumberWithCurrency(1000, { locale: 'en-US' }) // '$1,000' -formatNumberWithCurrency(1000, { locale: 'ko-KR-UNIT' }) // '1,000원' -formatNumberWithCurrency(1000, { locale: 'ko-KR' }) // '₩1,000' -formatNumberWithCurrency(1000, { locale: 'ja-JP' }) // '¥1,000' -formatNumberWithCurrency(1000, { locale: 'zh-CN' }) // '¥1,000' -formatNumberWithCurrency(1000, { locale: 'zh-HK' }) // 'HK$1,000' -formatNumberWithCurrency(1000, { locale: 'en-GB' }) // '£1,000' - -// 음수 처리 -formatNumberWithCurrency(-1000, { locale: 'ko-KR' }) // '-₩1,000' - -// 소숫점 처리 -formatNumberWithCurrency(1000.234, { locale: 'en-US' }) // '$1,000.234' -``` diff --git a/docs/docs/utils/formatter/formatValueWithSymbol.md b/docs/docs/utils/formatter/formatValueWithSymbol.md new file mode 100644 index 000000000..d909b442f --- /dev/null +++ b/docs/docs/utils/formatter/formatValueWithSymbol.md @@ -0,0 +1,67 @@ +# formatValueWithSymbol + +주어진 `숫자` 또는 `문자열`에 주어진 `기호`를 추가하는 함수입니다. + +- 기호는 `prefix` 또는 `suffix` 위치에 추가할 수 있습니다. +- `음수` 값의 경우 기호 앞에 `-`가 추가됩니다. +- 기호와 값 사이에 `공백`을 추가할 수 있습니다. + +
+ +## Code +[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/formatter/formatValueWithSymbol/index.ts) + +## Interface +```ts title="typescript" +interface FormatValueWithSymbolOptions { + symbol?: string; + position?: 'prefix' | 'suffix'; + space?: boolean; +} +``` +```ts title="typescript" +function formatValueWithSymbol( + value: number | string, + options?: FormatValueWithSymbolOptions +): string; +``` + +## Usage +```ts title="typescript" +import { formatValueWithSymbol } from '@modern-kit/utils'; + +// 통화 기호 추가 (기본 값: '') +formatValueWithSymbol(1000) // '1000' +formatValueWithSymbol(1000, { symbol: '원' }) // '1000원' + +// 통호 기호 위치 변경 (기본값: 'suffix') +formatValueWithSymbol(1000, { symbol: '$', position: 'prefix' }) // '$1000' +formatValueWithSymbol(1000, { symbol: '원', position: 'suffix' }) // '1000원' + +// 공백 추가 (기본값: false) +formatValueWithSymbol(1000, { symbol: '$', position: 'prefix', space: false }) // '$1000' +formatValueWithSymbol(1000, { symbol: '$', position: 'prefix', space: true }) // '$ 1000' +``` + +
+ +### 응용 +```ts title="typescript" +import { + formatValueWithSymbol, + formatNumberWithCommas, + formatNumberWithUnits +} from '@modern-kit/utils'; + +const KRW_UNITS = [ + { unit: '조', value: 1_000_000_000_000 }, + { unit: '억', value: 100_000_000 }, + { unit: '만', value: 10_000 }, +] as const; + +const numberWithCommas = formatNumberWithCommas(1234567); // 1,234,567 +const numberWithKRWUnits = formatNumberWithUnits(1230000, { units: KRW_UNITS }); // 123만 + +formatValueWithSymbol(numberWithKRWUnits, { symbol: '원' }) // '123만원' +formatValueWithSymbol(numberWithCommas, { symbol: '원' }) // '1,234,567원' +``` diff --git a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.constants.ts b/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.constants.ts deleted file mode 100644 index c6bfb84d8..000000000 --- a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.constants.ts +++ /dev/null @@ -1,25 +0,0 @@ -export const LOCALE_CURRENCY_MAP = { - 'ko-KR': { currency: 'KRW' }, // 대한민국 - 'en-US': { currency: 'USD' }, // 미국 - 'ja-JP': { currency: 'JPY' }, // 일본 - 'zh-CN': { currency: 'CNY' }, // 중국 - 'de-DE': { currency: 'EUR' }, // 독일 - 'en-GB': { currency: 'GBP' }, // 영국 - 'fr-FR': { currency: 'EUR' }, // 프랑스 - 'it-IT': { currency: 'EUR' }, // 이탈리아 - 'es-ES': { currency: 'EUR' }, // 스페인 - 'nl-NL': { currency: 'EUR' }, // 네덜란드 - 'pt-PT': { currency: 'EUR' }, // 포르투갈 - 'zh-HK': { currency: 'HKD' }, // 홍콩 - 'ru-RU': { currency: 'RUB' }, // 러시아 - 'ar-SA': { currency: 'SAR' }, // 사우디아라비아 - 'tr-TR': { currency: 'TRY' }, // 터키 - 'vi-VN': { currency: 'VND' }, // 베트남 - 'th-TH': { currency: 'THB' }, // 태국 - 'id-ID': { currency: 'IDR' }, // 인도네시아 - 'my-MY': { currency: 'MYR' }, // 말레이시아 - 'ph-PH': { currency: 'PHP' }, // 필리핀 - 'sg-SG': { currency: 'SGD' }, // 싱가포르 - 'nz-NZ': { currency: 'NZD' }, // 뉴질랜드 - // 필요 시 추가 -} as const; diff --git a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.spec.ts b/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.spec.ts deleted file mode 100644 index 351b88dbc..000000000 --- a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.spec.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { formatNumberWithCurrency } from './index'; -import { Locale } from './formatNumberWithCurrency.types'; - -describe('formatNumberWithCurrency', () => { - describe('기본 동작', () => { - it('옵션 없이 호출하면 기본 옵션으로 포맷팅되어야 합니다.', () => { - expect(formatNumberWithCurrency(1000)).toBe('1,000'); - expect(formatNumberWithCurrency(1000.123)).toBe('1,000.123'); - }); - - it('기본적으로 접미사(suffix) 위치에 통화 기호를 추가해야 합니다.', () => { - expect(formatNumberWithCurrency(1000, { symbol: '원' })).toBe('1,000원'); - expect(formatNumberWithCurrency(1000.123, { symbol: '원' })).toBe( - '1,000.123원' - ); - }); - - it('숫자로 이뤄진 문자열도 정상적으로 포맷팅되어야 합니다.', () => { - expect(formatNumberWithCurrency('1000', { symbol: '원' })).toBe( - '1,000원' - ); - expect(formatNumberWithCurrency('1000.123', { symbol: '원' })).toBe( - '1,000.123원' - ); // 소수 - }); - - it('음수일 때 통화 기호를 앞에 추가해야 합니다.', () => { - expect( - formatNumberWithCurrency(-1000, { symbol: '$', position: 'prefix' }) - ).toBe('-$1,000'); - expect( - formatNumberWithCurrency('-1000', { symbol: '$', position: 'prefix' }) - ).toBe('-$1,000'); - }); - }); - - describe('옵션 적용', () => { - it('position 옵션을 기반으로 기호를 추가해야 합니다.', () => { - expect( - formatNumberWithCurrency(1000, { - symbol: '$', - position: 'prefix', - }) - ).toBe('$1,000'); - - expect( - formatNumberWithCurrency(1000, { - symbol: '$', - position: 'suffix', - }) - ).toBe('1,000$'); - }); - - it('space가 true일 때 통화 기호와 숫자 사이에 공백을 추가해야 합니다.', () => { - expect( - formatNumberWithCurrency(1000, { - symbol: '$', - position: 'prefix', - space: true, - }) - ).toBe('$ 1,000'); - - expect( - formatNumberWithCurrency(1000, { - symbol: '$', - position: 'prefix', - space: false, - }) - ).toBe('$1,000'); - }); - - it('commas 옵션을 기반으로 쉼표를 추가해야 합니다.', () => { - expect( - formatNumberWithCurrency(1000, { - symbol: '$', - position: 'prefix', - commas: true, - }) - ).toBe('$1,000'); - - expect( - formatNumberWithCurrency(1000, { - symbol: '$', - position: 'prefix', - commas: false, - }) - ).toBe('$1000'); - }); - - it('locale 옵션이 있으면 locale 옵션에 따라 통화 기호가 적용되어야 합니다.', () => { - expect( - formatNumberWithCurrency(1000, { - locale: 'en-US', // { symbol: '$', position: 'prefix', space: false, commas: true } - }) - ).toBe('$1,000'); - - expect( - formatNumberWithCurrency(1000, { - locale: 'ko-KR', // { symbol: '₩', position: 'prefix', space: false, commas: true } - }) - ).toBe('₩1,000'); - - expect( - formatNumberWithCurrency(-1000, { - locale: 'ko-KR', // { symbol: '₩', position: 'prefix', space: false, commas: true } - }) - ).toBe('-₩1,000'); - - // 소수점 처리 - expect( - formatNumberWithCurrency(1000.123, { - locale: 'en-US', // { symbol: '$', position: 'prefix', space: false, commas: true } - }) - ).toBe('$1,000.123'); - }); - }); - - describe('에러 처리', () => { - it('숫자가 아닌 값이 주어지면 에러를 던져야 합니다.', () => { - expect(() => formatNumberWithCurrency('10d00')).toThrow( - 'value는 숫자 혹은 숫자로 이뤄진 문자열이여야 합니다.' - ); - }); - - it('지원하지 않는 locale 입력시 에러를 던져야 합니다.', () => { - expect(() => - formatNumberWithCurrency(1000, { - locale: 'INVALID' as unknown as Locale, - }) - ).toThrow('유효하지 않은 locale 입니다.'); - }); - }); -}); diff --git a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.types.ts b/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.types.ts deleted file mode 100644 index 82cf2a472..000000000 --- a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LOCALE_CURRENCY_MAP } from './formatNumberWithCurrency.constants'; - -export type Locale = keyof typeof LOCALE_CURRENCY_MAP; - -export interface FormatNumberCurrencyOptions { - symbol?: string; - position?: 'prefix' | 'suffix'; - space?: boolean; - commas?: boolean; - locale?: Locale; -} diff --git a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.utils.ts b/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.utils.ts deleted file mode 100644 index 608b32eff..000000000 --- a/packages/utils/src/formatter/formatNumberWithCurrency/formatNumberWithCurrency.utils.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { formatNumberWithCommas } from '../../formatter/formatNumberWithCommas'; -import { FormatNumberCurrencyOptions } from './formatNumberWithCurrency.types'; - -/** - * @description 숫자에 통화 기호를 추가하는 함수입니다. - * - * @param {number | string} value - 통화 기호를 추가할 숫자 또는 문자열 - * @param {FormatNumberCurrencyOptions & { isNegative: boolean }} options - 통화 단위 옵션 - * @param {string} [options.symbol=''] - 통화 기호 - * @param {'prefix' | 'suffix'} [options.position='suffix'] - 통화 기호 위치 - * @param {boolean} [options.space=false] - 숫자와 통화 기호 사이 공백 여부 - * @returns {string} 통화 기호가 추가된 문자열 - */ -export const getFormattedNumberWithCurrency = ( - value: number, - options: FormatNumberCurrencyOptions & { - isNegative: boolean; - } -): string => { - const { symbol, position, space, commas, isNegative } = options; - - const valueToUse = commas ? formatNumberWithCommas(value) : String(value); - - if (position === 'prefix') { - // 음수 처리 - if (isNegative) { - const numericPart = valueToUse.slice(1); - return '-' + symbol + (space ? ' ' : '') + numericPart; - } - return symbol + (space ? ' ' : '') + valueToUse; - } - return valueToUse + (space ? ' ' : '') + symbol; -}; diff --git a/packages/utils/src/formatter/formatNumberWithCurrency/index.ts b/packages/utils/src/formatter/formatNumberWithCurrency/index.ts deleted file mode 100644 index b289e522e..000000000 --- a/packages/utils/src/formatter/formatNumberWithCurrency/index.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { isNumber } from '../../validator/isNumber'; -import { LOCALE_CURRENCY_MAP } from './formatNumberWithCurrency.constants'; -import { - FormatNumberCurrencyOptions, - Locale, -} from './formatNumberWithCurrency.types'; -import { getFormattedNumberWithCurrency } from './formatNumberWithCurrency.utils'; - -/** - * @description `숫자 혹은 숫자로 이뤄진 문자열`을 주어진 `통화 기호`를 추가하는 함수입니다. - * - * 옵션이 없으면 기본값을 바탕으로 포맷팅됩니다. - * (기본 값: symbol: '', position: 'suffix', space: false, commas: true) - * - * @param {number | string} value - 포맷팅할 숫자 값 - * @returns {string} 통화 기호가 포함된 포맷팅된 문자열 - * - * @example - * // 기본 사용법 - * formatNumberWithCurrency(1000) // '1,000' - * formatNumberWithCurrency(-1000) // '-1,000' - */ -export function formatNumberWithCurrency(value: number | string): string; - -/** - * @description `숫자 혹은 숫자로 이뤄진 문자열`을 주어진 `통화 기호`를 추가하는 함수입니다. - * - * `locale` 옵션을 제외한, `기본 옵션`이 주어지면 주어진 옵션에 따라 포맷팅됩니다. - * (기본 옵션: `symbol`, `position`, `space`, `commas`) - * - * @param {number | string} value - 포맷팅할 숫자 값 - * @param {Omit} options - 포맷팅 옵션 - * @param {string} [options.symbol=''] - 통화 기호 - * @param {'prefix' | 'suffix'} [options.position='suffix'] - 통화 기호 위치 - * @param {boolean} [options.space=false] - 숫자와 통화 기호 사이 공백 여부 - * @param {boolean} [options.commas=true] - 천의 단위 구분 여부 - * @returns {string} 통화 기호가 포함된 포맷팅된 문자열 - * - * @example - * // 통화 기호(symbol) - * formatNumberWithCurrency(1000, { symbol: '원' }) // '1,000원' - * formatNumberWithCurrency(1000.123, { symbol: '원' }) // '1,000.123원' - * formatNumberWithCurrency(-1000, { symbol: '원' }) // '-1,000.123원' - * - * @example - * // 통화 기호 위치(position) - * formatNumberWithCurrency(1000, { symbol: '$', position: 'prefix' }) // '$1,000' - * - * @example - * // 기호와 숫자 사이 공백(space) - * formatNumberWithCurrency(1000, { symbol: '원', space: true }) // '1,000 원' - * - * @example - * // 천의 단위 구분 여부(commas) - * formatNumberWithCurrency(1000, { symbol: '원', commas: false }) // '1000원' - * formatNumberWithCurrency(1000, { symbol: '원', commas: true }) // '1,000원' - * - */ -export function formatNumberWithCurrency( - value: number | string, - options: Omit -): string; - -/** - * @description `숫자 혹은 숫자로 이뤄진 문자열`을 주어진 `통화 기호`를 추가하는 함수입니다. - * - * `locale` 옵션이 있으면 `locale` 형식에 따라 포맷팅됩니다. - * - * @param {number | string} value - 포맷팅할 숫자 값 - * @param {{ locale: Locale }} options - 포맷팅 옵션 - * @param {Locale} [options.locale] - 통화 단위 - * @returns {string} 통화 기호가 포함된 포맷팅된 문자열 - * - * @example - * // locale 옵션 적용 - * formatNumberWithCurrency(1000, { locale: 'en-US' }) // '$1,000' - * formatNumberWithCurrency(1000, { locale: 'ko-KR' }) // '₩1,000' - * formatNumberWithCurrency(1000, { locale: 'ja-JP' }) // '¥1,000' - * - * // 소수점 처리 - * formatNumberWithCurrency(1000.123, { locale: 'en-US' }) // '$1,000.123' - * formatNumberWithCurrency(1000.123, { locale: 'ko-KR' }) // '₩1,000.123' - * formatNumberWithCurrency(1000.123, { locale: 'ja-JP' }) // '¥1,000.123' - */ -export function formatNumberWithCurrency( - value: number | string, - options: { locale: Locale } -): string; - -/** - * @description `숫자 혹은 숫자로 이뤄진 문자열`을 주어진 `통화 기호`를 추가하는 함수입니다. - * - * @param {number | string} value - 포맷팅할 숫자 값 - * @param {FormatNumberCurrencyOptions} options - 포맷팅 옵션 - * @param {string} [options.symbol=''] - 통화 기호 - * @param {'prefix' | 'suffix'} [options.position='suffix'] - 통화 기호 위치 - * @param {boolean} [options.space=false] - 숫자와 통화 기호 사이 공백 여부 - * @param {boolean} [options.commas=true] - 천의 단위 구분 여부 - * @param {Locale} [options.locale] - 통화 단위 - * @returns {string} 통화 기호가 포함된 포맷팅된 문자열 - * - * @example - * // 기본 사용법 - * formatNumberWithCurrency(1000) // '1,000' - * - * // 통화 기호 추가 (기본값: '') - * formatNumberWithCurrency(1000, { symbol: '원' }) // '1,000원' - * - * // 음수 처리 - * formatNumberWithCurrency(-1000, { symbol: '$', position: 'prefix' }) // '-$1,000' - * - * // 숫자로 이뤄진 문자열 허용 - * formatNumberWithCurrency('1000', { symbol: '원' }) // '1,000원' - * - * @example - * // 통호 기호 위치 변경 (기본값: 'suffix') - * formatNumberWithCurrency(1000, { symbol: '$', position: 'prefix' }) // '$1,000' - * - * // 공백 추가 (기본값: false) - * formatNumberWithCurrency(1000, { symbol: '원', space: true }) // '1,000 원' - * - * // 천의 단위 구분 여부 (기본값: true) - * formatNumberWithCurrency(1000, { symbol: '원', commas: false }) // '1000원' - * formatNumberWithCurrency(1000, { symbol: '원', commas: true }) // '1,000원' - * - * @example - * // locale 옵션 적용 - * // locale 옵션이 있으면 그 외 옵션들은 무시됩니다. - * formatNumberWithCurrency(1000, { locale: 'en-US' }) // '$1,000' - * formatNumberWithCurrency(1000, { locale: 'ko-KR' }) // '₩1,000' - * formatNumberWithCurrency(1000, { locale: 'ko-KR-UNIT' }) // '1,000원' - */ -export function formatNumberWithCurrency( - value: number | string, - options: FormatNumberCurrencyOptions = {} -): string { - const { - symbol = '', - position = 'suffix', - space = false, - commas = true, - locale, - } = options; - const valueToUse = isNumber(value) ? value : Number(value); - const isNegative = valueToUse < 0; - - // 에러 처리 - if (isNaN(valueToUse)) { - throw new Error('value는 숫자 혹은 숫자로 이뤄진 문자열이여야 합니다.'); - } - - // locale 옵션 처리 - if (locale) { - if (!LOCALE_CURRENCY_MAP[locale]) { - throw new Error('유효하지 않은 locale 입니다.'); - } - - return valueToUse.toLocaleString(locale, { - style: 'currency', - currency: LOCALE_CURRENCY_MAP[locale].currency, - minimumFractionDigits: 0, - maximumFractionDigits: 20, - }); - } - - return getFormattedNumberWithCurrency(valueToUse, { - symbol, - position, - space, - commas, - isNegative, - }); -} diff --git a/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.spec.ts b/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.spec.ts new file mode 100644 index 000000000..7e9938648 --- /dev/null +++ b/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.spec.ts @@ -0,0 +1,74 @@ +import { describe, it, expect } from 'vitest'; +import { formatValueWithSymbol } from './index'; + +describe('formatNumberWithSymbol', () => { + describe('기본 동작', () => { + it('옵션 없이 호출하면 문자열로 변환 후 반환해야 합니다.', () => { + expect(formatValueWithSymbol(1000)).toBe('1000'); + }); + + it('기본적으로 접미사(suffix) 위치에 기호를 추가해야 합니다.', () => { + expect(formatValueWithSymbol(1000, { symbol: '원' })).toBe('1000원'); + }); + + it('음수일 때 "-" 기호를 앞에 추가해야 합니다.', () => { + expect( + formatValueWithSymbol(-1000, { symbol: '$', position: 'prefix' }) + ).toBe('-$1000'); + }); + + it('문자열도 정상적으로 포맷팅되어야 합니다.', () => { + expect(formatValueWithSymbol('1000', { symbol: '원' })).toBe('1000원'); + expect(formatValueWithSymbol('1,234,567', { symbol: '원' })).toBe( + '1,234,567원' + ); + + // 음수 처리 + expect( + formatValueWithSymbol('-1,234,567', { symbol: '$', position: 'prefix' }) + ).toBe('-$1,234,567'); + }); + + it('좌우 공백은 제거 후 포맷팅되어야 합니다.', () => { + expect(formatValueWithSymbol(' 1000 ', { symbol: '원' })).toBe( + '1000원' + ); + }); + }); + + describe('옵션 적용', () => { + it('position 옵션을 기반으로 기호를 추가해야 합니다.', () => { + expect( + formatValueWithSymbol(1000, { + symbol: '$', + position: 'prefix', + }) + ).toBe('$1000'); + + expect( + formatValueWithSymbol(1000, { + symbol: '원', + position: 'suffix', + }) + ).toBe('1000원'); + }); + + it('space가 true일 때 기호와 숫자 사이에 공백을 추가해야 합니다.', () => { + expect( + formatValueWithSymbol(1000, { + symbol: '$', + position: 'prefix', + space: true, + }) + ).toBe('$ 1000'); + + expect( + formatValueWithSymbol(1000, { + symbol: '$', + position: 'prefix', + space: false, + }) + ).toBe('$1000'); + }); + }); +}); diff --git a/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.types.ts b/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.types.ts new file mode 100644 index 000000000..4fa6b8316 --- /dev/null +++ b/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.types.ts @@ -0,0 +1,5 @@ +export interface FormatNumberWithSymbolOptions { + symbol?: string; + position?: 'prefix' | 'suffix' | 'both'; + space?: boolean; +} diff --git a/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.utils.ts b/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.utils.ts new file mode 100644 index 000000000..443df2e7b --- /dev/null +++ b/packages/utils/src/formatter/formatValueWithSymbol/formatValueWithSymbol.utils.ts @@ -0,0 +1,35 @@ +import { FormatNumberWithSymbolOptions } from './formatValueWithSymbol.types'; + +/** + * @description 주어진 문자열에 기호를 추가하는 내부 유틸리티 함수입니다. + * + * - 기호는 `prefix` 또는 `suffix` 위치에 추가할 수 있습니다. + * - 음수 값의 경우 기호 앞에 `-`가 추가됩니다. + * - 기호와 값 사이에 공백을 추가할 수 있습니다. + * + * @param {number | string} value - 통화 기호를 추가할 숫자 또는 문자열 + * @param {FormatNumberWithSymbolOptions & { isNegative: boolean }} options - 포맷팅 옵션 + * @param {string} [options.symbol=''] - 추가할 기호 + * @param {'prefix' | 'suffix'} [options.position='suffix'] - 기호 위치 + * @param {boolean} [options.space=false] - 숫자와 기호 사이 공백 여부 + * @returns {string} 기호가 추가된 포맷팅된 문자열 + */ +export const getFormattedNumberWithSymbol = ( + value: string, + options: FormatNumberWithSymbolOptions & { + isNegative: boolean; + } +): string => { + const { symbol, position, space, isNegative } = options; + + const spaceToUse = space ? ' ' : ''; + + if (position === 'prefix') { + if (isNegative) { + const numericPart = value.slice(1); + return '-' + symbol + spaceToUse + numericPart; + } + return symbol + spaceToUse + value; + } + return value + spaceToUse + symbol; +}; diff --git a/packages/utils/src/formatter/formatValueWithSymbol/index.ts b/packages/utils/src/formatter/formatValueWithSymbol/index.ts new file mode 100644 index 000000000..5d9aa102e --- /dev/null +++ b/packages/utils/src/formatter/formatValueWithSymbol/index.ts @@ -0,0 +1,53 @@ +import { FormatNumberWithSymbolOptions } from './formatValueWithSymbol.types'; +import { getFormattedNumberWithSymbol } from './formatValueWithSymbol.utils'; + +/** + * @description 주어진 `숫자` 또는 `문자열`의 원하는 위치에 주어진 `기호`를 추가하는 함수입니다. + * + * - 기호는 `prefix` 또는 `suffix` 위치에 추가할 수 있습니다. + * - 음수일 경우 기호 앞에 `-`가 추가됩니다. + * - 기호와 값 사이에 `공백`을 추가할 수 있습니다. + * + * @param {number | string} value - 포맷팅할 숫자 값 + * @param {FormatNumberWithSymbolOptions} options - 포맷팅 옵션 + * @param {string} [options.symbol=''] - 추가할 기호 + * @param {'prefix' | 'suffix'} [options.position='suffix'] - 기호 위치 + * @param {boolean} [options.space=false] - 숫자와 기호 사이 공백 여부 + * @returns {string} 기호가 추가된 포맷팅된 문자열 + * + * @example + * // 옵션 없이 호출하면 문자열로 변환된 숫자를 반환합니다. + * formatValueWithSymbol(1000) // '1000' + * + * // 기호 추가 (기본값: '') + * formatValueWithSymbol(1000, { symbol: '원' }) // '1000원' + * + * // 음수 처리 + * formatValueWithSymbol(-1000, { symbol: '$', position: 'prefix' }) // '-$1000' + * + * // 기호 위치 변경 (기본값: 'suffix') + * formatValueWithSymbol(1000, { symbol: '$', position: 'prefix' }) // '$1000' + * + * // 공백 추가 (기본값: false) + * formatValueWithSymbol(1000, { symbol: '원', space: true }) // '1000 원' + * + * // 문자열 처리 + * formatValueWithSymbol('1000', { symbol: '원' }) // '1000원' + * formatValueWithSymbol(123만, { symbol: '원' }) // '123만원' + * formatValueWithSymbol('1,234,567', { symbol: '원' }) // '1,234,567원' + */ +export function formatValueWithSymbol( + value: number | string, + options: FormatNumberWithSymbolOptions = {} +): string { + const { symbol = '', position = 'suffix', space = false } = options; + const valueToUse = String(value).trim(); + const isNegative = valueToUse.startsWith('-'); + + return getFormattedNumberWithSymbol(valueToUse, { + symbol, + position, + space, + isNegative, + }); +} diff --git a/packages/utils/src/formatter/index.ts b/packages/utils/src/formatter/index.ts index 4c9192339..58c0b0414 100644 --- a/packages/utils/src/formatter/index.ts +++ b/packages/utils/src/formatter/index.ts @@ -1,4 +1,4 @@ export * from './formatNumberWithCommas'; -export * from './formatNumberWithCurrency'; export * from './formatNumberWithUnits'; export * from './formatPhoneNumber'; +export * from './formatValueWithSymbol';