object.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import type { Flatten } from '@vben-core/typings';
  2. import {
  3. capitalizeFirstLetter,
  4. toLowerCaseFirstLetter,
  5. } from '@vben-core/toolkit';
  6. /**
  7. * 生成驼峰命名法的键名
  8. * @param key
  9. * @param parentKey
  10. */
  11. function toCamelCase(key: string, parentKey: string): string {
  12. if (!parentKey) {
  13. return key;
  14. }
  15. return parentKey + key.charAt(0).toUpperCase() + key.slice(1);
  16. }
  17. /**
  18. * 将嵌套对象扁平化
  19. * @param obj - 需要扁平化的对象
  20. * @param parentKey - 父键名,用于递归时拼接键名
  21. * @param result - 存储结果的对象
  22. * @returns 扁平化后的对象
  23. *
  24. * 示例:
  25. * const nestedObj = {
  26. * user: {
  27. * name: 'Alice',
  28. * address: {
  29. * city: 'Wonderland',
  30. * zip: '12345'
  31. * }
  32. * },
  33. * items: [
  34. * { id: 1, name: 'Item 1' },
  35. * { id: 2, name: 'Item 2' }
  36. * ],
  37. * active: true
  38. * };
  39. * const flatObj = flattenObject(nestedObj);
  40. * console.log(flatObj);
  41. * 输出:
  42. * {
  43. * userName: 'Alice',
  44. * userAddressCity: 'Wonderland',
  45. * userAddressZip: '12345',
  46. * items: [ { id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' } ],
  47. * active: true
  48. * }
  49. */
  50. function flattenObject<T extends Record<string, any>>(
  51. obj: T,
  52. parentKey: string = '',
  53. result: Record<string, any> = {},
  54. ): Flatten<T> {
  55. Object.keys(obj).forEach((key) => {
  56. const newKey = parentKey
  57. ? `${parentKey}${capitalizeFirstLetter(key)}`
  58. : key;
  59. const value = obj[key];
  60. if (value && typeof value === 'object' && !Array.isArray(value)) {
  61. flattenObject(value, newKey, result);
  62. } else {
  63. result[newKey] = value;
  64. }
  65. });
  66. return result as Flatten<T>;
  67. }
  68. /**
  69. * 将扁平对象转换为嵌套对象。
  70. *
  71. * @template T - 输入对象值的类型
  72. * @param {Record<string, T>} obj - 要转换的扁平对象
  73. * @param {number} level - 嵌套的层级
  74. * @returns {T} 嵌套对象
  75. *
  76. * @example
  77. * 将扁平对象转换为嵌套对象,嵌套层级为 1
  78. * const flatObject = {
  79. * 'commonAppName': 1,
  80. * 'anotherKeyExample': 2,
  81. * 'someOtherKey': 3
  82. * };
  83. * const nestedObject = toNestedObject(flatObject, 1);
  84. * console.log(nestedObject);
  85. * 输出:
  86. * {
  87. * commonAppName: 1,
  88. * anotherKeyExample: 2,
  89. * someOtherKey: 3
  90. * }
  91. *
  92. * @example
  93. * 将扁平对象转换为嵌套对象,嵌套层级为 2
  94. * const flatObject = {
  95. * 'appCommonName': 1,
  96. * 'appAnotherKeyExample': 2,
  97. * 'appSomeOtherKey': 3
  98. * };
  99. * const nestedObject = toNestedObject(flatObject, 2);
  100. * console.log(nestedObject);
  101. * 输出:
  102. * {
  103. * app: {
  104. * commonName: 1,
  105. * anotherKeyExample: 2,
  106. * someOtherKey: 3
  107. * }
  108. * }
  109. */
  110. function toNestedObject<T>(obj: Record<string, T>, level: number): T {
  111. const result: any = {};
  112. for (const key in obj) {
  113. const keys = key.split(/(?=[A-Z])/);
  114. // 将驼峰式分割为数组;
  115. let current = result;
  116. for (let i = 0; i < keys.length; i++) {
  117. const lowerKey = keys[i].toLowerCase();
  118. if (i === level - 1) {
  119. const remainingKeys = keys.slice(i).join(''); // 保留后续部分作为键的一部分
  120. current[toLowerCaseFirstLetter(remainingKeys)] = obj[key];
  121. break;
  122. } else {
  123. current[lowerKey] = current[lowerKey] || {};
  124. current = current[lowerKey];
  125. }
  126. }
  127. }
  128. return result as T;
  129. }
  130. export { flattenObject, toCamelCase, toNestedObject };
  131. // 定义递归类型,用于推断扁平化后的对象类型
  132. // 限制递归深度的辅助类型
  133. // type FlattenDepth<
  134. // T,
  135. // Depth extends number,
  136. // CurrentDepth extends number[] = [],
  137. // > = {
  138. // [K in keyof T as CurrentDepth['length'] extends Depth
  139. // ? K
  140. // : T[K] extends object
  141. // ? `${CurrentDepth['length'] extends 0 ? Uncapitalize<K & string> : Capitalize<K & string>}${keyof FlattenDepth<T[K], Depth, [...CurrentDepth, 1]> extends string ? Capitalize<keyof FlattenDepth<T[K], Depth, [...CurrentDepth, 1]>> : ''}`
  142. // : `${CurrentDepth['length'] extends 0 ? Uncapitalize<K & string> : Capitalize<K & string>}`]: CurrentDepth['length'] extends Depth
  143. // ? T[K]
  144. // : T[K] extends object
  145. // ? FlattenDepth<T[K], Depth, [...CurrentDepth, 1]>[keyof FlattenDepth<
  146. // T[K],
  147. // Depth,
  148. // [...CurrentDepth, 1]
  149. // >]
  150. // : T[K];
  151. // };
  152. // type Flatten<T, Depth extends number = 4> = FlattenDepth<T, Depth>;