From 41a42238f4f700f5c2531fb4627a740cb7119b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gromit=20=28=EC=A0=84=EB=AF=BC=EC=9E=AC=29?= <64779472+ssi02014@users.noreply.github.com> Date: Mon, 13 Jan 2025 20:17:02 +0900 Subject: [PATCH] =?UTF-8?q?SwitchCase=20=ED=95=98=EC=9C=84=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8/=EB=A6=AC?= =?UTF-8?q?=EC=95=A1=ED=8A=B8=20=EB=B2=84=EC=A0=84=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=ED=98=B8=ED=99=98=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#677)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(react): SwitchCase 하위 타입스크립트/리액트 버전 타입 호환성을 위해 반환 타입 수정 * fix: formatNumberWithUnits 소수점 처리 개선 --- .changeset/large-carrots-share.md | 5 ++ docs/docs/react/components/SwithCase.mdx | 23 +++--- .../utils/formatter/formatNumberWithUnits.md | 16 +++- .../react/src/components/SwitchCase/index.tsx | 8 +- .../formatNumberWithUnits.spec.ts | 9 +-- .../formatNumberWithUnits.utils.ts | 77 ++++--------------- .../formatter/formatNumberWithUnits/index.ts | 22 +++--- 7 files changed, 64 insertions(+), 96 deletions(-) create mode 100644 .changeset/large-carrots-share.md diff --git a/.changeset/large-carrots-share.md b/.changeset/large-carrots-share.md new file mode 100644 index 000000000..7e36fd3c1 --- /dev/null +++ b/.changeset/large-carrots-share.md @@ -0,0 +1,5 @@ +--- +'@modern-kit/react': patch +--- + +fix(react): SwitchCase 하위 타입스크립트/리액트 버전 타입 호환성을 위해 반환 타입 수정 - @ssi02014 diff --git a/docs/docs/react/components/SwithCase.mdx b/docs/docs/react/components/SwithCase.mdx index 7c2d3ecd7..cad37c499 100644 --- a/docs/docs/react/components/SwithCase.mdx +++ b/docs/docs/react/components/SwithCase.mdx @@ -16,19 +16,18 @@ import { SwitchCase } from '@modern-kit/react'; ## Interface ```ts title="typescript" -type Component = Nullable; - -interface SwitchCaseProps { - condition: Condition | null | undefined; - cases: Partial>; - defaultCaseComponent?: Component; +interface SwitchCaseProps { + value: Case | null | undefined; + caseBy: Record; + defaultComponent?: React.ReactNode; } - -const SwitchCase: ({ - condition, - cases, - defaultCaseComponent, -}: SwitchCaseProps) => JSX.Element; +``` +```ts title="typescript" +const SwitchCase: ({ + caseBy, + value, + defaultComponent, +}: SwitchCaseProps) => JSX.Element; ``` ## Usage diff --git a/docs/docs/utils/formatter/formatNumberWithUnits.md b/docs/docs/utils/formatter/formatNumberWithUnits.md index 1bd6558e3..c7edddee9 100644 --- a/docs/docs/utils/formatter/formatNumberWithUnits.md +++ b/docs/docs/utils/formatter/formatNumberWithUnits.md @@ -2,6 +2,11 @@ `숫자` 혹은 `숫자로 이루어진 문자열`을 주어진 `단위` 별로 포맷팅하는 함수입니다. +- 버림 단위(`floorUnit`)를 선택할 수 있습니다. +- 소수 일 경우 소수점 자리수(`decimal`)를 선택할 수 있습니다. 단, 버림 단위가 존재할 경우 소수 부분은 제거됩니다. +- 단위 사이 공백 추가 여부(`space`)를 선택할 수 있습니다. +- 쉼표 사용 여부(`commas`)를 선택할 수 있습니다. +
## Code @@ -80,12 +85,21 @@ formatNumberWithUnits(1234567, { units: KRW_UNITS, space: true }) // "123만 4,5 formatNumberWithUnits(1234567, { units: KRW_UNITS, space: false }) // "123만4,567" // 쉼표 사용 여부 (기본값: true) -formatNumberWithUnits(1234567, { units: KRW_UNITS, commas: false }) // "123만 4567" formatNumberWithUnits(1234567, { units: KRW_UNITS, commas: true }) // "123만 4,567" +formatNumberWithUnits(1234567, { units: KRW_UNITS, commas: false }) // "123만 4567" // 버림 단위 (기본값: 1) +formatNumberWithUnits(1234567, { units: KRW_UNITS, floorUnit: 1000 }) // "123만 4000" formatNumberWithUnits(1234567, { units: KRW_UNITS, floorUnit: 10000 }) // "123만" // 소수점 자리수 (기본값: 0) formatNumberWithUnits(1234567.123, { units: KRW_UNITS, decimal: 2 }) // "123만 4,567.12" + +// floorUnit이 1000으로 설정되어 있어서 1000 단위 미만은 버림 처리되고, +// decimal이 2로 설정되어 있지만 floorUnit 단위 만큼 버림 처리 되었으므로 소수는 표시되지 않습니다. +formatNumberWithUnits(1234567.123, { + units: KRW_UNITS, + decimal: 2, + floorUnit: 1000 +}) // "123만 4,000" ``` \ No newline at end of file diff --git a/packages/react/src/components/SwitchCase/index.tsx b/packages/react/src/components/SwitchCase/index.tsx index 27e987985..ad0a8c5d8 100644 --- a/packages/react/src/components/SwitchCase/index.tsx +++ b/packages/react/src/components/SwitchCase/index.tsx @@ -15,7 +15,7 @@ interface SwitchCaseProps { * @param {Record} props.caseBy - `value` 값에 대응하는 컴포넌트들을 담은 객체 * @param {React.ReactNode} props.defaultComponent - `value`가 `null`이거나 `caseBy`에 해당하는 컴포넌트가 없을 때 렌더링할 기본 컴포넌트 * - * @returns {React.ReactNode} - 조건부로 렌더링된 컴포넌트 + * @returns {JSX.Element} - 조건부로 렌더링된 컴포넌트 * * @example * ```tsx @@ -30,10 +30,10 @@ export const SwitchCase = ({ caseBy, value, defaultComponent = null, -}: SwitchCaseProps): React.ReactNode => { +}: SwitchCaseProps): JSX.Element => { if (isNil(value)) { - return defaultComponent; + return <>{defaultComponent}; } - return caseBy[value] ?? defaultComponent; + return <>{caseBy[value] ?? defaultComponent}; }; diff --git a/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.spec.ts b/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.spec.ts index 365a0f5ef..feb92add6 100644 --- a/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.spec.ts +++ b/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.spec.ts @@ -119,7 +119,8 @@ describe('formatNumberWithUnits', () => { formatNumberWithUnits(1234567.123, { decimal: 2, units: KRW_UNITS }) ).toBe('123만 4,567.12'); - // floorUnit이 주어지면 소수점 자리수를 적용하지 않습니다. + // floorUnit이 1000으로 설정되어 있어서 1000 단위 미만은 버림 처리되고, + // decimal이 2로 설정되어 있지만 floorUnit 단위 만큼 버림 처리 되었으므로 소수는 표시되지 않습니다. expect( formatNumberWithUnits(1234567.123, { decimal: 2, @@ -143,12 +144,6 @@ describe('formatNumberWithUnits', () => { ).toThrow('floorUnit은 1을 포함한 10의 제곱수여야 합니다.'); }); - it('floorUnit가 value의 절대값보다 작으면 예외를 발생시킵니다.', () => { - expect(() => - formatNumberWithUnits(1234567, { floorUnit: 1000000000 }) - ).toThrow('floorUnit 값은 value의 절대값보다 크거나 같아야 합니다.'); - }); - it('decimal이 0보다 작으면 예외를 발생시킵니다.', () => { expect(() => formatNumberWithUnits(1234567, { decimal: -1 as unknown as number }) diff --git a/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.utils.ts b/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.utils.ts index b8914b3a8..7f431a369 100644 --- a/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.utils.ts +++ b/packages/utils/src/formatter/formatNumberWithUnits/formatNumberWithUnits.utils.ts @@ -1,12 +1,6 @@ import { formatNumberWithCommas } from '../../formatter/formatNumberWithCommas'; import { FormatNumberWithUnitsOptions } from './formatNumberWithUnits.types'; -interface FormatOptions - extends Omit, 'units' | 'floorUnit'> { - value: number; - unit: string; -} - /** * @description 쉼표 사용 여부에 따라 숫자를 포맷팅하는 함수 * @@ -21,46 +15,6 @@ const formatNumberWithConditionalCommas = ( return commas ? formatNumberWithCommas(value) : String(value); }; -/** - * @description 남은 값을 포맷팅하는 내부 유틸 함수 - * - * @param {FormatOptions} options - 포맷팅 옵션 - * @param {number} options.decimal - 소수점 자리수 - * @param {boolean} options.commas - 쉼표 사용 여부 - * @returns {string} 포맷팅된 문자열 - */ -const formatRemainingValue = ({ - value, - decimal, - commas, -}: Omit): string => { - const formattedValue = Number.isInteger(value) - ? value - : value.toFixed(decimal); - return formatNumberWithConditionalCommas(formattedValue, commas); -}; - -/** - * @description 숫자에 단위를 추가하고 포맷팅하는 내부 유틸 함수 - * - * @param {FormatOptions} options - 포맷팅 옵션 - * @param {number} options.value - 포맷팅할 숫자 - * @param {string} options.unit - 단위 - * @param {boolean} options.commas - 쉼표 사용 여부 - * @param {boolean} options.space - 단위 사이 공백 추가 여부 - * @returns {string} 포맷팅된 문자열 - */ -const formatUnitValue = ({ - value, - unit, - commas, - space, -}: Omit): string => { - return `${formatNumberWithConditionalCommas(value, commas)}${unit}${ - space ? ' ' : '' - }`; -}; - /** * @description 주어진 단위(units)에 따라 숫자를 포맷팅하는 함수 * @@ -80,16 +34,18 @@ export const getFormattedValueWithUnits = ( const absoluteValue = Math.abs(value); const isNegative = value < 0; + const hasFloorUnit = floorUnit > 1; + let formattedResult = ''; let remainingValue = absoluteValue; - // value가 floorUnit(버림 단위)보다 작으면 '0'을 반환 + // value의 절대값이 floorUnit(버림 단위)보다 작으면 '0'을 반환 if (absoluteValue < floorUnit) { - throw new Error('floorUnit 값은 value의 절대값보다 크거나 같아야 합니다.'); + return '0'; } // floorUnit이 1보다 큰 경우, 최종 결과에서 floorUnit 미만의 값은 버림 - if (floorUnit > 1) { + if (hasFloorUnit) { remainingValue = Math.floor(remainingValue / floorUnit) * floorUnit; } @@ -97,25 +53,26 @@ export const getFormattedValueWithUnits = ( for (let i = 0; i < units.length; i++) { const { unit, value } = units[i]; const quotient = Math.floor(remainingValue / value); + const spaceToUse = space ? ' ' : ''; if (quotient <= 0) continue; - formattedResult += formatUnitValue({ - value: quotient, - unit, - commas, - space, - }); + formattedResult += `${formatNumberWithConditionalCommas( + quotient, + commas + )}${unit}${spaceToUse}`; remainingValue %= value; } // 남은 remainingValue가 있으면 추가 if (remainingValue > 0) { - formattedResult += formatRemainingValue({ - value: remainingValue, - decimal, - commas, - }); + // floorUnit이 주어지고, 정수가 아니라면 소수점 자리수를 적용 + const shouldApplyDecimal = !hasFloorUnit && !Number.isInteger(value); + + formattedResult += formatNumberWithConditionalCommas( + remainingValue.toFixed(shouldApplyDecimal ? decimal : 0), + commas + ); } // 음수일 경우 앞에 '-' 붙이며, 앞/뒤 공백 제거 diff --git a/packages/utils/src/formatter/formatNumberWithUnits/index.ts b/packages/utils/src/formatter/formatNumberWithUnits/index.ts index a6cd301f6..c3ee139fa 100644 --- a/packages/utils/src/formatter/formatNumberWithUnits/index.ts +++ b/packages/utils/src/formatter/formatNumberWithUnits/index.ts @@ -5,6 +5,11 @@ import { FormatNumberWithUnitsOptions } from './formatNumberWithUnits.types'; /** * @description `숫자` 혹은 `숫자로 이루어진 문자열`을 주어진 `단위` 별로 포맷팅하는 함수입니다. * + * - 버림 단위(`floorUnit`)를 선택할 수 있습니다. + * - 소수 일 경우 소수점 자리수(`decimal`)를 선택할 수 있습니다. 단, 버림 단위가 존재할 경우 소수 부분은 제거됩니다. + * - 단위 사이 공백 추가 여부(`space`)를 선택할 수 있습니다. + * - 쉼표 사용 여부(`commas`)를 선택할 수 있습니다. + * * @param {number | string} value - 포맷팅할 숫자 또는 숫자로 이루어진 문자열 * @param {FormatNumberWithUnitsOptions} options - 포맷팅 옵션 * @param {Unit[]} [options.units=DEFAULT_UNITS] - 사용할 단위 배열(조,억,만). 직접 정의해서 사용할 수 있습니다. @@ -34,23 +39,21 @@ import { FormatNumberWithUnitsOptions } from './formatNumberWithUnits.types'; * * @example * // 쉼표 사용 여부 (기본값: true) - * formatNumberWithUnits(1234567, { units: KRW_UNITS, commas: false }) // "123만 4567" * formatNumberWithUnits(1234567, { units: KRW_UNITS, commas: true }) // "123만 4,567" + * formatNumberWithUnits(1234567, { units: KRW_UNITS, commas: false }) // "123만 4567" * * @example * // 버림 단위 (기본값: 1) + * formatNumberWithUnits(1234567, { units: KRW_UNITS, floorUnit: 1000 }) // "123만 4000" * formatNumberWithUnits(1234567, { units: KRW_UNITS, floorUnit: 10000 }) // "123만" * * @example * // 소수점 자리수 (기본값: 0) * formatNumberWithUnits(1234567.123, { units: KRW_UNITS, decimal: 2 }) // "123만 4,567.12" * - * // floorUnit이 1보다 크면 소수점 자리수를 적용하지 않습니다. - * formatNumberWithUnits(1234567.123, { - * units: KRW_UNITS, - * decimal: 3, - * floorUnit: 1000 - * }) // "123만 4,000" + * // floorUnit이 1000으로 설정되어 있어서 1000 단위 미만은 버림 처리되고, + * // decimal이 2로 설정되어 있지만 floorUnit 단위 만큼 버림 처리 되었으므로 소수는 표시되지 않습니다. + * formatNumberWithUnits(1234567.123, { units: KRW_UNITS, decimal: 2, floorUnit: 1000 }) // "123만 4,000" */ export function formatNumberWithUnits( value: number | string, @@ -86,11 +89,6 @@ export function formatNumberWithUnits( throw new Error('decimal은 0 이상의 정수여야 합니다.'); } - // 0일 경우 바로 반환 - if (valueToUse === 0) { - return '0'; - } - // 포맷팅 return getFormattedValueWithUnits(valueToUse, { units: sortedUnits,