Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
commonUtil,
formatUtil,
searchQueryUtil,
typeUtil,
deviceUtil,
} from "kr-corekit";

Expand Down Expand Up @@ -73,6 +74,10 @@ const copied = await commonUtil.copyToClipboard("Hello, World!"); // true if suc
// Search Query utilities
const queryParams = searchQueryUtil.getAllQuery(); // { key: ["value1", "value2"], id: "123" }

// Type utilities
const isPlain = typeUtil.isPlainObject({}); // true
const isNotPlain = typeUtil.isPlainObject(new Date()); // false

// Device utilities
const device = deviceUtil.getDevice(); // { isMobile: false, isTablet: false, isDesktop: true, isIOS: false, isAndroid: false }

Expand Down Expand Up @@ -125,6 +130,10 @@ const formattedPhone = formatUtil.formatPhoneNumber("01012345678"); // "010-1234

- `getAllQuery(): Record<string, string | string[]>` - Parses the current URL's query string and returns an object with key-value pairs. Values appear as arrays when the same key is used multiple times.

### TypeUtil

- `isPlainObject(value: unknown): boolean` - Checks if a value is a plain object (created by Object literal or Object.create(null)), excluding arrays, dates, and other built-in objects.

### DeviceUtil

- `getDevice(): DeviceInfo` - Detects the user's device environment. Returns information about device type (mobile/tablet/desktop) and operating system (iOS/Android). Uses navigator.userAgent for detection and provides safe fallback for SSR environments.
Expand Down
12 changes: 12 additions & 0 deletions package/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
// 네임스페이스에 대한 익스포트 진행
export * as stringUtil from "./stringUtil";
export * as objectUtil from "./objectUtil";
export * as cookieUtil from "./cookieUtil";
export * as numberUtil from "./numberUtil";
export * as validationUtil from "./validationUtil";
export * as commonUtil from "./commonUtil";
export * as searchQueryUtil from "./searchQueryUtil";
export * as typeUtil from "./typeUtil";

// 개별 함수에 대한 익스포트 진행
export * from "./stringUtil";
export * from "./objectUtil";
export * from "./cookieUtil";
export * from "./numberUtil";
export * from "./validationUtil";
export * from "./commonUtil";
export * from "./searchQueryUtil";
export * from "./typeUtil";
24 changes: 24 additions & 0 deletions package/objectUtil/clearNullProperties/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,27 @@ test("만약 Null이 객체에 존재한다면, Null이 없는 객체가 반환
const result = clearNullProperties(obj);
expect(result).toEqual({ a: 1, b: 2 });
});

test("만약 배열이 포함된 객체가 존재한다면, 그대로 반환된다.", () => {
const obj = { a: 1, b: [1, 2, 3], c: null };
const result = clearNullProperties(obj);
expect(result).toEqual({ a: 1, b: [1, 2, 3] });
});

test("만약 중첩된 객체가 존재한다면, 중첩된 객체의 Null도 제거된다.", () => {
const obj = { a: 1, b: { c: null, d: 4 }, e: null };
const result = clearNullProperties(obj);
expect(result).toEqual({ a: 1, b: { d: 4 } });
});

test("만약 모든 속성이 Null이라면, 빈 객체가 반환된다.", () => {
const obj = { a: null, b: null };
const result = clearNullProperties(obj);
expect(result).toEqual({});
});

test("만약 속성에 false 값이 존재한다면, false 값은 유지된다.", () => {
const obj = { a: false, b: null };
const result = clearNullProperties(obj);
expect(result).toEqual({ a: false });
});
25 changes: 16 additions & 9 deletions package/objectUtil/clearNullProperties/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import isPlainObject from "../../typeUtil/isPlainObject";

export default function clearNullProperties<T>(obj: T): T {
const result = { ...obj };
Object.keys(result as Record<string, any>).forEach((el) => {
if (!(result as Record<string, any>)[el]) {
delete (result as Record<string, any>)[el];
} else if (typeof (result as Record<string, any>)[el] === "object") {
(result as Record<string, any>)[el] = clearNullProperties((result as Record<string, any>)[el]);
}
})
return result;
const result = { ...obj };
Object.keys(result as Record<string, any>).forEach((el) => {
if (
(result as Record<string, any>)[el] === null ||
(result as Record<string, any>)[el] === undefined
) {
delete (result as Record<string, any>)[el];
} else if (isPlainObject((result as Record<string, any>)[el])) {
(result as Record<string, any>)[el] = clearNullProperties(
(result as Record<string, any>)[el]
);
}
});
return result;
}
1 change: 1 addition & 0 deletions package/typeUtil/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as isPlainObject } from "./isPlainObject";
28 changes: 28 additions & 0 deletions package/typeUtil/isPlainObject/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { describe, expect, test } from "vitest";
import isPlainObject from ".";

describe("isPlainObject 유틸 함수 테스트", () => {
test("일반 객체는 true를 반환한다", () => {
const obj = { a: 1, b: 2 };
expect(isPlainObject(obj)).toBe(true);
});

test("배열은 false를 반환한다", () => {
const arr = [1, 2, 3];
expect(isPlainObject(arr)).toBe(false);
});

test("null은 false를 반환한다", () => {
expect(isPlainObject(null)).toBe(false);
});

test("날짜 객체는 false를 반환한다", () => {
const date = new Date();
expect(isPlainObject(date)).toBe(false);
});

test("커스텀 프로토타입을 가진 객체는 false를 반환한다", () => {
const obj = Object.create({ a: 1 });
expect(isPlainObject(obj)).toBe(false);
});
});
10 changes: 10 additions & 0 deletions package/typeUtil/isPlainObject/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default function isPlainObject(value: unknown): boolean {
if (typeof value !== "object" || value === null) {
return false;
}

return (
Object.getPrototypeOf(value) === Object.prototype ||
Object.getPrototypeOf(value) === null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오.. 이것도 객체를 의미하는 줄 몰랐습니다..!! 👍

);
}