@simplysm/core-common 13.0.16 → 13.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/utils/obj.ts CHANGED
@@ -16,8 +16,8 @@ import { ArgumentError } from "../errors/argument-error";
16
16
  * @note 프로토타입 체인은 유지됨 (Object.setPrototypeOf 사용)
17
17
  * @note getter/setter는 현재 값으로 평가되어 복사됨 (접근자 속성 자체는 복사되지 않음)
18
18
  */
19
- export function objClone<T>(source: T): T {
20
- return objCloneImpl(source) as T;
19
+ export function objClone<TSource>(source: TSource): TSource {
20
+ return objCloneImpl(source) as TSource;
21
21
  }
22
22
 
23
23
  function objCloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): unknown {
@@ -433,21 +433,25 @@ export interface ObjMergeOptions {
433
433
  * 객체 배열의 경우 참조(주소) 비교로 중복을 판단함
434
434
  * @note 타입이 다른 경우 target 값으로 덮어씀
435
435
  */
436
- export function objMerge<T, P>(source: T, target: P, opt?: ObjMergeOptions): T & P {
436
+ export function objMerge<TSource, TMergeTarget>(
437
+ source: TSource,
438
+ target: TMergeTarget,
439
+ opt?: ObjMergeOptions,
440
+ ): TSource & TMergeTarget {
437
441
  if (source == null) {
438
- return objClone(target) as T & P;
442
+ return objClone(target) as TSource & TMergeTarget;
439
443
  }
440
444
 
441
445
  if (target === undefined) {
442
- return objClone(source) as T & P;
446
+ return objClone(source) as TSource & TMergeTarget;
443
447
  }
444
448
 
445
449
  if (target === null) {
446
- return opt?.useDelTargetNull ? (undefined as T & P) : (objClone(source) as T & P);
450
+ return opt?.useDelTargetNull ? (undefined as TSource & TMergeTarget) : (objClone(source) as TSource & TMergeTarget);
447
451
  }
448
452
 
449
453
  if (typeof target !== "object") {
450
- return target as T & P;
454
+ return target as TSource & TMergeTarget;
451
455
  }
452
456
 
453
457
  if (
@@ -459,12 +463,12 @@ export function objMerge<T, P>(source: T, target: P, opt?: ObjMergeOptions): T &
459
463
  target instanceof Uint8Array ||
460
464
  (opt?.arrayProcess === "replace" && target instanceof Array)
461
465
  ) {
462
- return objClone(target) as T & P;
466
+ return objClone(target) as TSource & TMergeTarget;
463
467
  }
464
468
 
465
469
  // source가 object가 아니거나, source와 target이 다른 종류의 object면 target으로 덮어씀
466
470
  if (typeof source !== "object" || source.constructor !== target.constructor) {
467
- return objClone(target) as T & P;
471
+ return objClone(target) as TSource & TMergeTarget;
468
472
  }
469
473
 
470
474
  if (source instanceof Map && target instanceof Map) {
@@ -476,7 +480,7 @@ export function objMerge<T, P>(source: T, target: P, opt?: ObjMergeOptions): T &
476
480
  result.set(key, objClone(target.get(key)));
477
481
  }
478
482
  }
479
- return result as T & P;
483
+ return result as TSource & TMergeTarget;
480
484
  }
481
485
 
482
486
  if (opt?.arrayProcess === "concat" && source instanceof Array && target instanceof Array) {
@@ -484,7 +488,7 @@ export function objMerge<T, P>(source: T, target: P, opt?: ObjMergeOptions): T &
484
488
  if (opt.useDelTargetNull) {
485
489
  result = result.filter((item) => item !== null);
486
490
  }
487
- return result as T & P;
491
+ return result as TSource & TMergeTarget;
488
492
  }
489
493
 
490
494
  const sourceRec = source as Record<string, unknown>;
@@ -497,7 +501,7 @@ export function objMerge<T, P>(source: T, target: P, opt?: ObjMergeOptions): T &
497
501
  }
498
502
  }
499
503
 
500
- return resultRec as T & P;
504
+ return resultRec as TSource & TMergeTarget;
501
505
  }
502
506
 
503
507
  /** merge3 옵션 타입 */
@@ -688,19 +692,23 @@ export function objGetChainValue(obj: unknown, chain: string, optional?: true):
688
692
  * @throws ArgumentError depth가 1 미만일 경우
689
693
  * @example objGetChainValueByDepth({ parent: { parent: { name: 'a' } } }, 'parent', 2) => { name: 'a' }
690
694
  */
691
- export function objGetChainValueByDepth<T, K extends keyof T>(
692
- obj: T,
693
- key: K,
695
+ export function objGetChainValueByDepth<TObject, TKey extends keyof TObject>(
696
+ obj: TObject,
697
+ key: TKey,
694
698
  depth: number,
695
699
  optional: true,
696
- ): T[K] | undefined;
697
- export function objGetChainValueByDepth<T, K extends keyof T>(obj: T, key: K, depth: number): T[K];
698
- export function objGetChainValueByDepth<T, K extends keyof T>(
699
- obj: T,
700
- key: K,
700
+ ): TObject[TKey] | undefined;
701
+ export function objGetChainValueByDepth<TObject, TKey extends keyof TObject>(
702
+ obj: TObject,
703
+ key: TKey,
704
+ depth: number,
705
+ ): TObject[TKey];
706
+ export function objGetChainValueByDepth<TObject, TKey extends keyof TObject>(
707
+ obj: TObject,
708
+ key: TKey,
701
709
  depth: number,
702
710
  optional?: true,
703
- ): T[K] | undefined {
711
+ ): TObject[TKey] | undefined {
704
712
  if (depth < 1) {
705
713
  throw new ArgumentError("depth는 1 이상이어야 합니다.", { depth });
706
714
  }
@@ -712,7 +720,7 @@ export function objGetChainValueByDepth<T, K extends keyof T>(
712
720
  result = (result as Record<string, unknown>)[key as string];
713
721
  }
714
722
  }
715
- return result as T[K] | undefined;
723
+ return result as TObject[TKey] | undefined;
716
724
  }
717
725
 
718
726
  /**
@@ -798,11 +806,11 @@ export function objClear<T extends Record<string, unknown>>(obj: T): Record<stri
798
806
  *
799
807
  * @mutates 원본 배열/객체를 직접 수정함
800
808
  */
801
- export function objNullToUndefined<T>(obj: T): T | undefined {
809
+ export function objNullToUndefined<TObject>(obj: TObject): TObject | undefined {
802
810
  return objNullToUndefinedImpl(obj, new WeakSet());
803
811
  }
804
812
 
805
- function objNullToUndefinedImpl<T>(obj: T, seen: WeakSet<object>): T | undefined {
813
+ function objNullToUndefinedImpl<TObject>(obj: TObject, seen: WeakSet<object>): TObject | undefined {
806
814
  if (obj == null) {
807
815
  return undefined;
808
816
  }
@@ -877,16 +885,16 @@ export function objUnflatten(flatObj: Record<string, unknown>): Record<string, u
877
885
  * undefined를 가진 프로퍼티를 optional로 변환
878
886
  * @example { a: string; b: string | undefined } → { a: string; b?: string | undefined }
879
887
  */
880
- export type ObjUndefToOptional<T> = {
881
- [K in keyof T as undefined extends T[K] ? K : never]?: T[K];
882
- } & { [K in keyof T as undefined extends T[K] ? never : K]: T[K] };
888
+ export type ObjUndefToOptional<TObject> = {
889
+ [K in keyof TObject as undefined extends TObject[K] ? K : never]?: TObject[K];
890
+ } & { [K in keyof TObject as undefined extends TObject[K] ? never : K]: TObject[K] };
883
891
 
884
892
  /**
885
893
  * optional 프로퍼티를 required + undefined 유니온으로 변환
886
894
  * @example { a: string; b?: string } → { a: string; b: string | undefined }
887
895
  */
888
- export type ObjOptionalToUndef<T> = {
889
- [K in keyof T]-?: {} extends Pick<T, K> ? T[K] | undefined : T[K];
896
+ export type ObjOptionalToUndef<TObject> = {
897
+ [K in keyof TObject]-?: {} extends Pick<TObject, K> ? TObject[K] | undefined : TObject[K];
890
898
  };
891
899
 
892
900
  //#endregion
@@ -918,7 +926,7 @@ export function objFromEntries<T extends [string, unknown]>(entries: T[]): { [K
918
926
  return Object.fromEntries(entries) as { [K in T[0]]: T[1] };
919
927
  }
920
928
 
921
- type ObjEntries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
929
+ type ObjEntries<TObject> = { [K in keyof TObject]: [K, TObject[K]] }[keyof TObject][];
922
930
 
923
931
  /**
924
932
  * 객체의 각 엔트리를 변환하여 새 객체 반환
@@ -936,20 +944,20 @@ type ObjEntries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
936
944
  * objMap(colors, (key, rgb) => [`${key}Light`, `rgb(${rgb})`]);
937
945
  * // { primaryLight: "rgb(255, 0, 0)", secondaryLight: "rgb(0, 255, 0)" }
938
946
  */
939
- export function objMap<T extends object, NK extends string, NV>(
940
- obj: T,
941
- fn: (key: keyof T, value: T[keyof T]) => [NK | null, NV],
942
- ): Record<NK | Extract<keyof T, string>, NV> {
947
+ export function objMap<TSource extends object, TNewKey extends string, TNewValue>(
948
+ obj: TSource,
949
+ fn: (key: keyof TSource, value: TSource[keyof TSource]) => [TNewKey | null, TNewValue],
950
+ ): Record<TNewKey | Extract<keyof TSource, string>, TNewValue> {
943
951
  return objMapImpl(obj, fn);
944
952
  }
945
953
 
946
- function objMapImpl<T extends object, NK extends string, NV>(
947
- obj: T,
948
- fn: (key: keyof T, value: T[keyof T]) => [NK | null, NV],
949
- ): Record<string, NV> {
950
- const result: Record<string, NV> = {};
954
+ function objMapImpl<TSource extends object, TNewKey extends string, TNewValue>(
955
+ obj: TSource,
956
+ fn: (key: keyof TSource, value: TSource[keyof TSource]) => [TNewKey | null, TNewValue],
957
+ ): Record<string, TNewValue> {
958
+ const result: Record<string, TNewValue> = {};
951
959
  for (const key of Object.keys(obj)) {
952
- const [newKey, newValue] = fn(key as keyof T, (obj as Record<string, T[keyof T]>)[key]);
960
+ const [newKey, newValue] = fn(key as keyof TSource, (obj as Record<string, TSource[keyof TSource]>)[key]);
953
961
  result[newKey ?? key] = newValue;
954
962
  }
955
963
  return result;