@movk/core 0.0.4 → 1.0.0

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/dist/index.d.mts CHANGED
@@ -1,38 +1,331 @@
1
- import { VNode, Ref } from 'vue';
1
+ import { MaybeRefOrGetter, VNode, Ref, Component, DefineComponent } from 'vue';
2
2
  import { z } from 'zod/v4';
3
3
 
4
+ /**
5
+ * 统一同步/异步返回类型
6
+ * @typeParam T - 类型
7
+ * @example
8
+ * // type T = string | Promise<string>
9
+ * // type R = ApiAwaitable<T>
10
+ * // 结果:R 为 string | Promise<string>
11
+ */
12
+ type ApiAwaitable<T> = T | Promise<T>;
13
+ /**
14
+ * 提取Promise类型
15
+ * @typeParam T - 类型
16
+ * @example
17
+ * // type T = Promise<string>
18
+ * // type R = ApiUnwrapPromise<T>
19
+ * // 结果:R 为 string
20
+ */
21
+ type ApiUnwrapPromise<T> = T extends Promise<infer U> ? U : T;
22
+ /**
23
+ * 提取函数返回类型
24
+ * @typeParam TFn - 函数类型
25
+ * @example
26
+ * // type Fn = (x: number, y: string) => Promise<string>
27
+ * // type R = ApiAwaitedReturn<Fn>
28
+ * // 结果:R 为 string
29
+ */
30
+ type ApiAwaitedReturn<TFn> = TFn extends (...args: any[]) => ApiAwaitable<infer R> ? R : never;
31
+
32
+ /**
33
+ * 提供字符串字面量提示的同时允许任意字符串
34
+ * 在 IDE 中提供 T 类型的自动补全提示,但不限制只能使用这些值
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * type Color = Suggest<'red' | 'blue' | 'green'>
39
+ *
40
+ * // IDE 会提示 'red', 'blue', 'green',但也可以使用其他字符串
41
+ * const color1: Color = 'red' // 有提示
42
+ * const color2: Color = 'yellow' // 也可以,虽然没有提示
43
+ * ```
44
+ */
45
+ type Suggest<T extends string> = T | (string & {});
46
+ /**
47
+ * 响应式值类型 - 基于 Vue 的 `MaybeRefOrGetter` 扩展,额外支持上下文回调
48
+ *
49
+ * @template T - 值类型
50
+ * @template CTX - 上下文类型(用于回调函数)
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const value: ReactiveValue<boolean> = ref(false)
55
+ * const getter: ReactiveValue<string> = () => name.value
56
+ * const computed: ReactiveValue<number> = computed(() => count.value)
57
+ * const withContext: ReactiveValue<boolean, Context> = (ctx) => ctx.value > 0
58
+ * ```
59
+ */
60
+ type ReactiveValue<T, CTX = never> = [CTX] extends [never] ? MaybeRefOrGetter<T> : MaybeRefOrGetter<T> | ((ctx: CTX) => T);
61
+ type StripNullable<T> = T extends null | undefined ? never : T;
62
+
63
+ type UnknownObject = Record<string, unknown>;
4
64
  type AnyObject = Record<string, any>;
65
+ /**
66
+ * 依据键名从对象类型 `T` 中剔除键 `K`。
67
+ * @typeParam T - 源对象类型
68
+ * @typeParam K - 要剔除的键(必须来自 `keyof T`)
69
+ * @example
70
+ * // type User = { id: string; name: string; age: number }
71
+ * // type R = OmitByKey<User, 'age'>
72
+ * // 结果:R 为 { id: string; name: string }
73
+ */
5
74
  type OmitByKey<T, K extends keyof T> = {
6
75
  [P in keyof T as P extends K ? never : P]: T[P];
7
76
  };
77
+ /**
78
+ * 依据键名从对象类型 `T` 中挑选键 `K`。
79
+ * @typeParam T - 源对象类型
80
+ * @typeParam K - 要保留的键(必须来自 `keyof T`)
81
+ * @example
82
+ * // type User = { id: string; name: string; age: number }
83
+ * // type R = PickByKey<User, 'id' | 'name'>
84
+ * // 结果:R 为 { id: string; name: string }
85
+ */
8
86
  type PickByKey<T, K extends keyof T> = {
9
87
  [P in keyof T as P extends K ? P : never]: T[P];
10
88
  };
89
+ /**
90
+ * 基于映射表 `Mapping` 对对象类型 `T` 的键进行重命名。
91
+ * 未在映射表中的键保持原名;映射值为 `PropertyKey`(string/number/symbol)。
92
+ * @typeParam T - 源对象类型
93
+ * @typeParam Mapping - 旧键到新键名的映射
94
+ * @example
95
+ * // type Src = { a: number; b: string }
96
+ * // type R = RenameKeys<Src, { a: 'id' }>
97
+ * // 结果:R 为 { id: number; b: string }
98
+ */
11
99
  type RenameKeys<T, Mapping extends {
12
100
  [K in keyof T]?: PropertyKey;
13
101
  }> = {
14
102
  [K in keyof T as K extends keyof Mapping ? Exclude<Mapping[K], undefined> : K]: T[K];
15
103
  };
104
+ /**
105
+ * 将对象类型 `T` 中的键 `K` 标记为必填(移除可选修饰)。
106
+ * @typeParam T - 源对象类型
107
+ * @typeParam K - 设为必填的键
108
+ * @example
109
+ * // type User = { id: string; name?: string }
110
+ * // type R = RequiredByKeys<User, 'name'>
111
+ * // 结果:R['name'] 为必填的 string
112
+ */
16
113
  type RequiredByKeys<T, K extends keyof T> = T & {
17
114
  [P in K]-?: T[P];
18
115
  };
116
+ /**
117
+ * 将对象类型 `T` 中的键 `K` 标记为可选。
118
+ * @typeParam T - 源对象类型
119
+ * @typeParam K - 设为可选的键
120
+ * @example
121
+ * // type User = { id: string; name: string }
122
+ * // type R = PartialByKeys<User, 'name'>
123
+ * // 结果:R['name'] 为可选(可能为 undefined)
124
+ */
19
125
  type PartialByKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
126
+ /**
127
+ * 将对象类型 `T` 中的键 `K` 标记为只读(浅只读)。
128
+ * @typeParam T - 源对象类型
129
+ * @typeParam K - 设为只读的键
130
+ * @example
131
+ * // type User = { id: string; name: string }
132
+ * // type R = ReadonlyByKeys<User, 'id'>
133
+ * // 结果:R['id'] 不可被重新赋值
134
+ */
20
135
  type ReadonlyByKeys<T, K extends keyof T> = T & {
21
136
  readonly [P in K]: T[P];
22
137
  };
138
+ /**
139
+ * 取消对象类型 `T` 中键 `K` 的只读限制,使其可写(浅层)。
140
+ * @typeParam T - 源对象类型
141
+ * @typeParam K - 取消只读的键
142
+ * @example
143
+ * // type User = { readonly id: string; name: string }
144
+ * // type R = MutableByKeys<User, 'id'>
145
+ * // 结果:R['id'] 变为可写
146
+ */
23
147
  type MutableByKeys<T, K extends keyof T> = {
24
148
  -readonly [P in K]: T[P];
25
149
  } & Omit<T, K>;
150
+ /**
151
+ * 将联合类型 `U` 转换为交叉类型,用于合并联合成员的属性。
152
+ * @typeParam U - 联合类型
153
+ * @example
154
+ * // type U = { a: number } | { b: string }
155
+ * // type R = UnionToIntersection<U>
156
+ * // 结果:R 为 { a: number } & { b: string }
157
+ */
26
158
  type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? {
27
159
  [K in keyof I]: I[K];
28
160
  } : never;
161
+ /**
162
+ * 若对象 `T` 在键 `K` 处的类型为元组,则提取其首个元素类型,否则为 `never`。
163
+ * @typeParam T - 具有元组属性的对象类型
164
+ * @typeParam K - 属性键
165
+ * @example
166
+ * // type Cfg = { params: [id: string, flag?: boolean] }
167
+ * // type R = FirstParam<Cfg, 'params'>
168
+ * // 结果:R 为 string
169
+ */
29
170
  type FirstParam<T, K extends keyof T> = T[K] extends [infer P, ...any[]] ? P : never;
171
+ /**
172
+ * 从函数类型中提取首个参数类型;若 `T` 非函数类型,则为 `undefined`。
173
+ * @typeParam T - 函数类型
174
+ * @example
175
+ * // type Fn = (x: number, y: string) => void
176
+ * // type R = FirstParameter<Fn>
177
+ * // 结果:R 为 number;若 T 非函数,则为 undefined
178
+ */
30
179
  type FirstParameter<T> = T extends (arg: infer P, ...args: any[]) => any ? P : undefined;
180
+ /**
181
+ * 递归将对象类型 `T` 的所有属性变为可选(深可选)。
182
+ * @typeParam T - 源对象类型
183
+ * @example
184
+ * // type Src = { a: { b: number } }
185
+ * // type R = DeepPartial<Src>
186
+ * // 结果:R 为 { a?: { b?: number | undefined } | undefined }
187
+ */
31
188
  type DeepPartial<T> = {
32
189
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P] | undefined;
33
190
  };
191
+ /**
192
+ * 当 `MaybeObject` 为对象时,返回键 `Key` 对应的属性类型;否则为 `never`。
193
+ * @typeParam MaybeObject - 可能为对象的类型
194
+ * @typeParam Key - 目标键名(string)
195
+ * @example
196
+ * // type Obj = { id: number }
197
+ * // type R1 = GetObjectField<Obj, 'id'> // 结果:number
198
+ * // type R2 = GetObjectField<string, 'id'> // 结果:never
199
+ */
34
200
  type GetObjectField<MaybeObject, Key extends string> = MaybeObject extends Record<string, any> ? MaybeObject[Key] : never;
201
+ /**
202
+ * Vue 渲染相关文本/节点类型:可为字符串、`VNode` 或返回 `VNode` 的函数。
203
+ * @example
204
+ * // 在渲染 API 中允许三种形态:
205
+ * // - '标题'
206
+ * // - h('div', '标题') 产生的 VNode
207
+ * // - () => h('div', '标题') 的惰性渲染函数
208
+ */
35
209
  type StringOrVNode = string | VNode | (() => VNode);
210
+ /**
211
+ * 合并两个对象类型,U 中的属性会覆盖 T 中的属性
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * type T = { a: number, c: string }
216
+ * type U = { a: string, b: boolean }
217
+ * type M = Merge<T, U> // { a: string, b: boolean, c: string }
218
+ * ```
219
+ */
220
+ type Merge<T, U> = Omit<T, keyof U> & U;
221
+ /**
222
+ * 判断类型 T 是否为纯对象类型
223
+ * 纯对象是指普通的对象字面量,排除数组、函数、Date 等特殊对象类型
224
+ * @example
225
+ * ```ts
226
+ * type Test1 = IsPlainObject<{ a: number }> // true
227
+ * type Test2 = IsPlainObject<string[]> // false
228
+ * type Test3 = IsPlainObject<() => void> // false
229
+ * type Test4 = IsPlainObject<Date> // false
230
+ * type Test5 = IsPlainObject<string> // false
231
+ * type Test6 = IsPlainObject<null> // false
232
+ * ```
233
+ */
234
+ type IsPlainObject<T> = (T extends null | undefined ? never : T) extends Record<string, any> ? (T extends null | undefined ? never : T) extends any[] ? false : (T extends null | undefined ? never : T) extends (...args: any[]) => any ? false : (T extends null | undefined ? never : T) extends Date ? false : true : false;
235
+ /**
236
+ * 深度控制类型,用于限制类型递归的深度
237
+ * 防止类型计算超出 TypeScript 的递归限制
238
+ */
239
+ type Depth = [never, 0, 1, 2, 3, 4];
240
+ /**
241
+ * 提取对象的嵌套键,支持点语法路径
242
+ *
243
+ * @template T 源对象类型
244
+ * @template D 递归深度,默认为2
245
+ * @example
246
+ * ```ts
247
+ * type User = {
248
+ * name: string
249
+ * address: {
250
+ * city: string
251
+ * country: string
252
+ * }
253
+ * }
254
+ * type Keys = NestedKeys<User> // 'name' | 'address' | 'address.city' | 'address.country'
255
+ * ```
256
+ */
257
+ type NestedKeys<T, D extends number = 2> = [D] extends [never] ? never : {
258
+ [K in keyof T & string]: IsPlainObject<T[K]> extends true ? K | `${K}.${NestedKeys<T[K] extends null | undefined ? never : T[K], Depth[D]>}` : K;
259
+ }[keyof T & string];
260
+ /**
261
+ * 提取对象中所有纯对象字段的键(包括嵌套的),支持点语法路径
262
+ *
263
+ * @template T 源对象类型
264
+ * @template D 递归深度,默认为2
265
+ * @example
266
+ * ```ts
267
+ * type User = {
268
+ * name: string
269
+ * age: number
270
+ * address: {
271
+ * city: string
272
+ * location: {
273
+ * lat: number
274
+ * lng: number
275
+ * }
276
+ * }
277
+ * }
278
+ * type ObjectKeys = ObjectFieldKeys<User> // 'address' | 'address.location'
279
+ * ```
280
+ */
281
+ type ObjectFieldKeys<T, D extends number = 2> = [D] extends [never] ? never : {
282
+ [K in keyof T & string]: IsPlainObject<T[K]> extends true ? K | `${K}.${ObjectFieldKeys<T[K] extends null | undefined ? never : T[K], Depth[D]>}` : never;
283
+ }[keyof T & string];
284
+ /**
285
+ * 提取对象中所有非对象字段的键
286
+ * 排除纯对象字段,只保留原始类型字段的键
287
+ *
288
+ * @template T 源对象类型
289
+ * @example
290
+ * ```ts
291
+ * type User = {
292
+ * name: string
293
+ * age: number
294
+ * address: {
295
+ * city: string
296
+ * }
297
+ * }
298
+ * type NonObjectKeys = NonObjectFieldKeys<User> // 'name' | 'age' | 'address.city'
299
+ * ```
300
+ */
301
+ type NonObjectFieldKeys<T> = Exclude<NestedKeys<T>, ObjectFieldKeys<T>>;
302
+ /**
303
+ * 提取对象中所有数组字段的键(包括嵌套的),支持点语法路径
304
+ *
305
+ * @template T 源对象类型
306
+ * @template D 递归深度,默认为2
307
+ * @example
308
+ * ```ts
309
+ * type User = {
310
+ * name: string
311
+ * tags: string[]
312
+ * posts: Array<{ title: string }>
313
+ * profile: {
314
+ * hobbies: string[]
315
+ * }
316
+ * }
317
+ * type ArrayKeys = ArrayFieldKeys<User> // 'tags' | 'posts' | 'profile.hobbies'
318
+ * ```
319
+ */
320
+ type ArrayFieldKeys<T, D extends number = 2> = [D] extends [never] ? never : {
321
+ [K in keyof T & string]: (T[K] extends null | undefined ? never : T[K]) extends any[] ? K : IsPlainObject<T[K]> extends true ? `${K}.${ArrayFieldKeys<T[K] extends null | undefined ? never : T[K], Depth[D]>}` : never;
322
+ }[keyof T & string];
323
+ /**
324
+ * 根据路径字符串提取对象属性的类型,支持点语法和嵌套对象
325
+ * @example GetFieldValue<User, 'tags'> // string[]
326
+ * @example GetFieldValue<User, 'profile.bio'> // string
327
+ */
328
+ type GetFieldValue<T, P extends string> = P extends keyof T ? T[P] : P extends `${infer K}.${infer Rest}` ? K extends keyof T ? T[K] extends undefined ? undefined : GetFieldValue<NonNullable<T[K]>, Rest> : unknown : unknown;
36
329
 
37
330
  declare const StorageTypeSchema: z.ZodEnum<{
38
331
  localStorage: "localStorage";
@@ -58,6 +351,38 @@ interface AppStorageReturn<T> {
58
351
  removeItem: () => void;
59
352
  }
60
353
 
354
+ /**
355
+ * vue-component-type-helpers
356
+ * Copy from https://github.com/vuejs/language-tools/tree/master/packages/component-type-helpers
357
+ */
358
+ type IsComponent = StringOrVNode | Component | DefineComponent | ((...args: any[]) => any);
359
+ type ComponentType<T> = T extends new (...args: any) => {} ? 1 : T extends (...args: any) => any ? 2 : 0;
360
+ type ComponentProps<T> = T extends new (...args: any) => {
361
+ $props: infer P;
362
+ } ? NonNullable<P> : T extends (props: infer P, ...args: any) => any ? P : {};
363
+ type ComponentSlots<T> = T extends new (...args: any) => {
364
+ $slots: infer S;
365
+ } ? NonNullable<S> : T extends (props: any, ctx: {
366
+ slots: infer S;
367
+ attrs: any;
368
+ emit: any;
369
+ }, ...args: any) => any ? NonNullable<S> : {};
370
+ type ComponentAttrs<T> = T extends new (...args: any) => {
371
+ $attrs: infer A;
372
+ } ? NonNullable<A> : T extends (props: any, ctx: {
373
+ slots: any;
374
+ attrs: infer A;
375
+ emit: any;
376
+ }, ...args: any) => any ? NonNullable<A> : {};
377
+ type ComponentEmit<T> = T extends new (...args: any) => {
378
+ $emit: infer E;
379
+ } ? NonNullable<E> : T extends (props: any, ctx: {
380
+ slots: any;
381
+ attrs: any;
382
+ emit: infer E;
383
+ }, ...args: any) => any ? NonNullable<E> : {};
384
+ type ComponentExposed<T> = T extends new (...args: any) => infer E ? E : T extends (props: any, ctx: any, expose: (exposed: infer E) => any, ...args: any) => any ? NonNullable<E> : {};
385
+
61
386
  /**
62
387
  * 应用存储管理的组合式函数,支持localStorage和sessionStorage
63
388
  *
@@ -141,532 +466,130 @@ declare function useAppStorage<T = unknown>(config: StorageConfigInput<T>): AppS
141
466
  */
142
467
  declare function useCopyCode(text: string): Promise<boolean>;
143
468
 
144
- type TreeNode<T = any> = T & {
145
- children?: TreeNode<T>[];
146
- [key: string]: any;
147
- };
148
- declare const TreeConfigSchema: z.ZodObject<{
149
- id: z.ZodDefault<z.ZodString>;
150
- pid: z.ZodDefault<z.ZodString>;
151
- children: z.ZodDefault<z.ZodString>;
152
- }, z.core.$strip>;
153
- type TreeConfigInput = z.input<typeof TreeConfigSchema>;
154
- declare const _TreeStatsSchema: z.ZodObject<{
155
- total: z.ZodNumber;
156
- leaves: z.ZodNumber;
157
- depth: z.ZodNumber;
158
- branches: z.ZodNumber;
159
- }, z.core.$strip>;
160
- type TreeStats = z.infer<typeof _TreeStatsSchema>;
161
- interface TreeNodeResult<T = any> {
162
- readonly node: TreeNode<T>;
163
- readonly path: readonly TreeNode<T>[];
164
- readonly depth: number;
165
- readonly index: number;
166
- }
167
- type TreePredicate<T = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => boolean;
168
- type TreeTransformer<T = any, R = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => R;
169
- type TreeVisitor<T = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => void | boolean;
170
- declare class Tree {
171
- private static dfsGenerator;
172
- private static bfsGenerator;
173
- private static selectStrategy;
174
- /**
175
- * 从扁平数组创建树形结构
176
- *
177
- * @category Data Structures
178
- * @param list 扁平数组数据
179
- * @param config 树形配置选项
180
- * @returns 树形结构数组
181
- * @example
182
- * ```ts
183
- * const flatData = [
184
- * { id: '1', name: '部门1', parentId: null },
185
- * { id: '2', name: '部门1-1', parentId: '1' },
186
- * { id: '3', name: '部门1-2', parentId: '1' },
187
- * { id: '4', name: '部门1-1-1', parentId: '2' }
188
- * ]
189
- *
190
- * const tree = Tree.fromList(flatData, {
191
- * id: 'id',
192
- * pid: 'parentId',
193
- * children: 'children'
194
- * })
195
- *
196
- * console.log(tree) // 转换为树形结构
197
- * ```
198
- */
199
- static fromList<T = any>(list: T[], config?: TreeConfigInput): TreeNode<T>[];
200
- /**
201
- * 将树形结构转换为扁平数组
202
- *
203
- * @category Data Structures
204
- * @param tree 树形结构(单个节点或节点数组)
205
- * @param config 树形配置选项
206
- * @returns 扁平数组
207
- * @example
208
- * ```ts
209
- * const tree = [
210
- * {
211
- * id: '1',
212
- * name: '根节点',
213
- * children: [
214
- * { id: '2', name: '子节点1', children: [] },
215
- * { id: '3', name: '子节点2', children: [] }
216
- * ]
217
- * }
218
- * ]
219
- *
220
- * const flatList = Tree.toList(tree)
221
- * console.log(flatList) // [{ id: '1', name: '根节点' }, { id: '2', name: '子节点1' }, ...]
222
- * ```
223
- */
224
- static toList<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): T[];
225
- /**
226
- * 估算树形结构的节点数量
227
- *
228
- * @category Data Structures
229
- * @param tree 树形结构(单个节点或节点数组)
230
- * @param config 树形配置选项
231
- * @returns 节点总数量
232
- * @example
233
- * ```ts
234
- * const tree = [
235
- * {
236
- * id: '1',
237
- * name: '根节点',
238
- * children: [
239
- * { id: '2', name: '子节点1', children: [] },
240
- * { id: '3', name: '子节点2', children: [] }
241
- * ]
242
- * }
243
- * ]
244
- *
245
- * const size = Tree.estimateSize(tree)
246
- * console.log(size) // 3
247
- * ```
248
- */
249
- static estimateSize<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): number;
250
- /**
251
- * 查找树中第一个满足条件的节点
252
- *
253
- * @category Data Structures
254
- * @param tree 树形结构(单个节点或节点数组)
255
- * @param predicate 查找条件函数
256
- * @param config 树形配置选项
257
- * @returns 匹配的节点结果,包含节点、路径、深度和索引信息;未找到时返回undefined
258
- * @example
259
- * ```ts
260
- * const tree = [
261
- * {
262
- * id: '1',
263
- * name: '部门1',
264
- * children: [
265
- * { id: '2', name: '部门1-1', children: [] }
266
- * ]
267
- * }
268
- * ]
269
- *
270
- * const result = Tree.find(tree, (node) => node.name === '部门1-1')
271
- * console.log(result?.node.id) // '2'
272
- * console.log(result?.depth) // 1
273
- * ```
274
- */
275
- static find<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
276
- /**
277
- * 查找树中所有满足条件的节点
278
- *
279
- * @category Data Structures
280
- * @param tree 树形结构(单个节点或节点数组)
281
- * @param predicate 查找条件函数
282
- * @param config 树形配置选项
283
- * @returns 所有匹配的节点结果数组,每个结果包含节点、路径、深度和索引信息
284
- * @example
285
- * ```ts
286
- * const tree = [
287
- * {
288
- * id: '1',
289
- * type: 'folder',
290
- * name: '根目录',
291
- * children: [
292
- * { id: '2', type: 'file', name: '文件1', children: [] },
293
- * { id: '3', type: 'file', name: '文件2', children: [] }
294
- * ]
295
- * }
296
- * ]
297
- *
298
- * const files = Tree.findAll(tree, (node) => node.type === 'file')
299
- * console.log(files.length) // 2
300
- * ```
301
- */
302
- static findAll<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T>[];
303
- /**
304
- * 根据ID查找树中的节点
305
- *
306
- * @category Data Structures
307
- * @param tree 树形结构(单个节点或节点数组)
308
- * @param id 要查找的节点ID
309
- * @param config 树形配置选项
310
- * @returns 匹配的节点结果,包含节点、路径、深度和索引信息;未找到时返回undefined
311
- * @example
312
- * ```ts
313
- * const tree = [
314
- * {
315
- * id: '1',
316
- * name: '根节点',
317
- * children: [
318
- * { id: '2', name: '子节点', children: [] }
319
- * ]
320
- * }
321
- * ]
322
- *
323
- * const result = Tree.findById(tree, '2')
324
- * console.log(result?.node.name) // '子节点'
325
- * ```
326
- */
327
- static findById<T = any>(tree: TreeNode<T> | TreeNode<T>[], id: string, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
328
- /**
329
- * 获取树形结构的统计信息
330
- *
331
- * @category Data Structures
332
- * @param tree 树形结构(单个节点或节点数组)
333
- * @param config 树形配置选项
334
- * @returns 树的统计信息,包含总节点数、叶子节点数、最大深度和分支节点数
335
- * @example
336
- * ```ts
337
- * const tree = [
338
- * {
339
- * id: '1',
340
- * name: '根节点',
341
- * children: [
342
- * { id: '2', name: '子节点1', children: [] },
343
- * { id: '3', name: '子节点2', children: [
344
- * { id: '4', name: '孙节点', children: [] }
345
- * ] }
346
- * ]
347
- * }
348
- * ]
349
- *
350
- * const stats = Tree.getStats(tree)
351
- * console.log(stats) // { total: 4, leaves: 2, depth: 3, branches: 2 }
352
- * ```
353
- */
354
- static getStats<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): TreeStats;
355
- /**
356
- * 过滤树形结构,保留满足条件的节点及其祖先和后代
357
- *
358
- * @category Data Structures
359
- * @param tree 树形结构(单个节点或节点数组)
360
- * @param predicate 过滤条件函数
361
- * @param config 树形配置选项
362
- * @returns 过滤后的树形结构数组
363
- * @example
364
- * ```ts
365
- * const tree = [
366
- * {
367
- * id: '1',
368
- * type: 'folder',
369
- * name: '根目录',
370
- * children: [
371
- * { id: '2', type: 'file', name: '文档.txt', children: [] },
372
- * { id: '3', type: 'folder', name: '子目录', children: [
373
- * { id: '4', type: 'file', name: '图片.jpg', children: [] }
374
- * ] }
375
- * ]
376
- * }
377
- * ]
378
- *
379
- * const filtered = Tree.filter(tree, (node) => node.type === 'file')
380
- * // 返回包含所有文件节点及其父级路径的树结构
381
- * ```
382
- */
383
- static filter<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNode<T>[];
384
- /**
385
- * 转换树形结构,将每个节点转换为新的结构
386
- *
387
- * @category Data Structures
388
- * @param tree 树形结构(单个节点或节点数组)
389
- * @param transformer 节点转换函数
390
- * @param config 树形配置选项
391
- * @returns 转换后的树形结构数组
392
- * @example
393
- * ```ts
394
- * const tree = [
395
- * {
396
- * id: '1',
397
- * name: '部门1',
398
- * children: [
399
- * { id: '2', name: '部门1-1', children: [] }
400
- * ]
401
- * }
402
- * ]
403
- *
404
- * const transformed = Tree.transform(tree, (node, depth) => ({
405
- * key: node.id,
406
- * title: node.name,
407
- * level: depth
408
- * }))
409
- * // 转换为新的数据结构
410
- * ```
411
- */
412
- static transform<T = any, R = any>(tree: TreeNode<T> | TreeNode<T>[], transformer: TreeTransformer<T, R>, config?: TreeConfigInput): TreeNode<R>[];
413
- /**
414
- * 遍历树形结构的每个节点
415
- *
416
- * @category Data Structures
417
- * @param tree 树形结构(单个节点或节点数组)
418
- * @param visitor 访问者函数,返回false可以跳过子节点的遍历
419
- * @param config 树形配置选项
420
- * @example
421
- * ```ts
422
- * const tree = [
423
- * {
424
- * id: '1',
425
- * name: '根节点',
426
- * children: [
427
- * { id: '2', name: '子节点', children: [] }
428
- * ]
429
- * }
430
- * ]
431
- *
432
- * Tree.forEach(tree, (node, depth) => {
433
- * console.log(`${' '.repeat(depth * 2)}${node.name}`)
434
- * // 输出缩进的树结构
435
- * })
436
- * ```
437
- */
438
- static forEach<T = any>(tree: TreeNode<T> | TreeNode<T>[], visitor: TreeVisitor<T>, config?: TreeConfigInput): void;
439
- /**
440
- * 在指定节点前插入新节点
441
- *
442
- * @category Data Structures
443
- * @param tree 树形结构数组
444
- * @param targetId 目标节点的ID
445
- * @param newNode 要插入的新节点数据
446
- * @param config 树形配置选项
447
- * @returns 是否成功插入
448
- * @example
449
- * ```ts
450
- * const tree = [
451
- * {
452
- * id: '1',
453
- * name: '节点1',
454
- * children: [
455
- * { id: '2', name: '节点2', children: [] }
456
- * ]
457
- * }
458
- * ]
459
- *
460
- * const success = Tree.insertBefore(tree, '2', { id: '1.5', name: '新节点' })
461
- * console.log(success) // true
462
- * ```
463
- */
464
- static insertBefore<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
465
- /**
466
- * 在指定节点后插入新节点
467
- *
468
- * @category Data Structures
469
- * @param tree 树形结构数组
470
- * @param targetId 目标节点的ID
471
- * @param newNode 要插入的新节点数据
472
- * @param config 树形配置选项
473
- * @returns 是否成功插入
474
- * @example
475
- * ```ts
476
- * const tree = [
477
- * {
478
- * id: '1',
479
- * name: '节点1',
480
- * children: [
481
- * { id: '2', name: '节点2', children: [] }
482
- * ]
483
- * }
484
- * ]
485
- *
486
- * const success = Tree.insertAfter(tree, '2', { id: '3', name: '新节点' })
487
- * console.log(success) // true
488
- * ```
489
- */
490
- static insertAfter<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
491
- /**
492
- * 从树中删除指定节点
493
- *
494
- * @category Data Structures
495
- * @param tree 树形结构数组
496
- * @param targetId 要删除的节点ID
497
- * @param config 树形配置选项
498
- * @returns 被删除的节点,未找到时返回undefined
499
- * @example
500
- * ```ts
501
- * const tree = [
502
- * {
503
- * id: '1',
504
- * name: '根节点',
505
- * children: [
506
- * { id: '2', name: '子节点', children: [] }
507
- * ]
508
- * }
509
- * ]
510
- *
511
- * const removed = Tree.remove(tree, '2')
512
- * console.log(removed?.name) // '子节点'
513
- * ```
514
- */
515
- static remove<T = any>(tree: TreeNode<T>[], targetId: string, config?: TreeConfigInput): TreeNode<T> | undefined;
516
- /**
517
- * 验证树形结构的有效性
518
- *
519
- * @category Data Structures
520
- * @param tree 树形结构(单个节点或节点数组)
521
- * @param config 树形配置选项
522
- * @returns 验证结果,包含是否有效和错误信息数组
523
- * @example
524
- * ```ts
525
- * const tree = [
526
- * {
527
- * id: '1',
528
- * name: '根节点',
529
- * children: [
530
- * { id: '2', name: '子节点', children: [] }
531
- * ]
532
- * }
533
- * ]
534
- *
535
- * const result = Tree.validate(tree)
536
- * console.log(result.isValid) // true
537
- * console.log(result.errors) // []
538
- * ```
539
- */
540
- static validate<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): {
541
- isValid: boolean;
542
- errors: string[];
543
- };
544
- }
545
-
546
- /**
547
- * 数组去重,返回去除重复元素后的新数组
548
- *
549
- * @category Array
550
- * @param arr 待去重的数组
551
- * @returns 去重后的新数组
552
- * @example
553
- * ```ts
554
- * const numbers = [1, 2, 2, 3, 3, 4]
555
- * const uniqueNumbers = unique(numbers)
556
- * console.log(uniqueNumbers) // [1, 2, 3, 4]
557
- *
558
- * const strings = ['a', 'b', 'a', 'c']
559
- * const uniqueStrings = unique(strings)
560
- * console.log(uniqueStrings) // ['a', 'b', 'c']
561
- * ```
562
- */
563
- declare function unique<T>(arr: T[]): T[];
564
- /**
565
- * 将数组分割成指定大小的块
566
- *
567
- * @category Array
568
- * @param arr 待分割的数组
569
- * @param size 每个块的大小
570
- * @returns 分割后的二维数组
571
- * @example
572
- * ```ts
573
- * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
574
- * const chunks = chunk(numbers, 3)
575
- * console.log(chunks) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
576
- *
577
- * const names = ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
578
- * const pairs = chunk(names, 2)
579
- * console.log(pairs) // [['Alice', 'Bob'], ['Charlie', 'David'], ['Eve']]
580
- * ```
581
- */
582
- declare function chunk<T>(arr: T[], size: number): T[][];
583
- /**
584
- * 数组扁平化,将嵌套数组展平到指定深度
585
- *
586
- * @category Array
587
- * @param arr 待扁平化的数组
588
- * @param depth 扁平化深度,默认为1
589
- * @returns 扁平化后的数组
590
- * @example
591
- * ```ts
592
- * const nested = [1, [2, 3], [4, [5, 6]]]
593
- * const flat1 = flatten(nested)
594
- * console.log(flat1) // [1, 2, 3, 4, [5, 6]]
595
- *
596
- * const flat2 = flatten(nested, 2)
597
- * console.log(flat2) // [1, 2, 3, 4, 5, 6]
598
- * ```
599
- */
600
- declare function flatten<T>(arr: T[], depth?: number): any[];
601
-
602
- /**
603
- * 防抖函数,在指定时间内多次触发只执行最后一次
604
- *
605
- * @category Async
606
- * @param func 需要防抖的函数
607
- * @param wait 防抖延迟时间(毫秒)
608
- * @returns 防抖处理后的函数
609
- * @example
610
- * ```ts
611
- * const debouncedSearch = debounce((query: string) => {
612
- * console.log('搜索:', query)
613
- * }, 300)
614
- *
615
- * // 连续调用,只有最后一次会执行
616
- * debouncedSearch('a')
617
- * debouncedSearch('ab')
618
- * debouncedSearch('abc') // 只有这次会在300ms后执行
619
- * ```
620
- */
621
- declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
622
-
623
- /**
624
- * 延迟执行函数,返回一个在指定时间后resolve的Promise
625
- *
626
- * @category Async
627
- * @param ms 延迟时间(毫秒)
628
- * @returns 延迟Promise
629
- * @example
630
- * ```ts
631
- * // 延迟1秒后继续执行
632
- * await sleep(1000)
633
- * console.log('1秒后执行')
634
- *
635
- * // 在异步函数中使用
636
- * async function delayedOperation() {
637
- * console.log('开始')
638
- * await sleep(500)
639
- * console.log('500ms后执行')
640
- * }
641
- * ```
642
- */
643
- declare function sleep(ms: number): Promise<void>;
644
- /**
645
- * 可取消的延迟函数,返回Promise和取消函数
646
- *
647
- * @category Async
648
- * @param ms 延迟时间(毫秒)
649
- * @returns 包含Promise和取消函数的对象
650
- * @example
651
- * ```ts
652
- * const { promise, cancel } = sleepWithCancel(5000)
653
- *
654
- * // 在另一个地方取消延迟
655
- * setTimeout(() => {
656
- * cancel() // 取消延迟
657
- * }, 2000)
658
- *
659
- * try {
660
- * await promise
661
- * console.log('5秒后执行')
662
- * } catch (error) {
663
- * console.log('延迟被取消')
664
- * }
665
- * ```
666
- */
667
- declare function sleepWithCancel(ms: number): {
668
- promise: Promise<void>;
669
- cancel: () => void;
469
+ /**
470
+ * 数组去重,返回去除重复元素后的新数组
471
+ *
472
+ * @category Array
473
+ * @param arr 待去重的数组
474
+ * @returns 去重后的新数组
475
+ * @example
476
+ * ```ts
477
+ * const numbers = [1, 2, 2, 3, 3, 4]
478
+ * const uniqueNumbers = unique(numbers)
479
+ * console.log(uniqueNumbers) // [1, 2, 3, 4]
480
+ *
481
+ * const strings = ['a', 'b', 'a', 'c']
482
+ * const uniqueStrings = unique(strings)
483
+ * console.log(uniqueStrings) // ['a', 'b', 'c']
484
+ * ```
485
+ */
486
+ declare function unique<T>(arr: T[]): T[];
487
+ /**
488
+ * 将数组分割成指定大小的块
489
+ *
490
+ * @category Array
491
+ * @param arr 待分割的数组
492
+ * @param size 每个块的大小
493
+ * @returns 分割后的二维数组
494
+ * @example
495
+ * ```ts
496
+ * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
497
+ * const chunks = chunk(numbers, 3)
498
+ * console.log(chunks) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
499
+ *
500
+ * const names = ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
501
+ * const pairs = chunk(names, 2)
502
+ * console.log(pairs) // [['Alice', 'Bob'], ['Charlie', 'David'], ['Eve']]
503
+ * ```
504
+ */
505
+ declare function chunk<T>(arr: T[], size: number): T[][];
506
+ /**
507
+ * 数组扁平化,将嵌套数组展平到指定深度
508
+ *
509
+ * @category Array
510
+ * @param arr 待扁平化的数组
511
+ * @param depth 扁平化深度,默认为1
512
+ * @returns 扁平化后的数组
513
+ * @example
514
+ * ```ts
515
+ * const nested = [1, [2, 3], [4, [5, 6]]]
516
+ * const flat1 = flatten(nested)
517
+ * console.log(flat1) // [1, 2, 3, 4, [5, 6]]
518
+ *
519
+ * const flat2 = flatten(nested, 2)
520
+ * console.log(flat2) // [1, 2, 3, 4, 5, 6]
521
+ * ```
522
+ */
523
+ declare function flatten<T>(arr: T[], depth?: number): any[];
524
+
525
+ /**
526
+ * 防抖函数,在指定时间内多次触发只执行最后一次
527
+ *
528
+ * @category Async
529
+ * @param func 需要防抖的函数
530
+ * @param wait 防抖延迟时间(毫秒)
531
+ * @returns 防抖处理后的函数
532
+ * @example
533
+ * ```ts
534
+ * const debouncedSearch = debounce((query: string) => {
535
+ * console.log('搜索:', query)
536
+ * }, 300)
537
+ *
538
+ * // 连续调用,只有最后一次会执行
539
+ * debouncedSearch('a')
540
+ * debouncedSearch('ab')
541
+ * debouncedSearch('abc') // 只有这次会在300ms后执行
542
+ * ```
543
+ */
544
+ declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
545
+
546
+ /**
547
+ * 延迟执行函数,返回一个在指定时间后resolve的Promise
548
+ *
549
+ * @category Async
550
+ * @param ms 延迟时间(毫秒)
551
+ * @returns 延迟Promise
552
+ * @example
553
+ * ```ts
554
+ * // 延迟1秒后继续执行
555
+ * await sleep(1000)
556
+ * console.log('1秒后执行')
557
+ *
558
+ * // 在异步函数中使用
559
+ * async function delayedOperation() {
560
+ * console.log('开始')
561
+ * await sleep(500)
562
+ * console.log('500ms后执行')
563
+ * }
564
+ * ```
565
+ */
566
+ declare function sleep(ms: number): Promise<void>;
567
+ /**
568
+ * 可取消的延迟函数,返回Promise和取消函数
569
+ *
570
+ * @category Async
571
+ * @param ms 延迟时间(毫秒)
572
+ * @returns 包含Promise和取消函数的对象
573
+ * @example
574
+ * ```ts
575
+ * const { promise, cancel } = sleepWithCancel(5000)
576
+ *
577
+ * // 在另一个地方取消延迟
578
+ * setTimeout(() => {
579
+ * cancel() // 取消延迟
580
+ * }, 2000)
581
+ *
582
+ * try {
583
+ * await promise
584
+ * console.log('5秒后执行')
585
+ * } catch (error) {
586
+ * console.log('延迟被取消')
587
+ * }
588
+ * ```
589
+ */
590
+ declare function sleepWithCancel(ms: number): {
591
+ promise: Promise<void>;
592
+ cancel: () => void;
670
593
  };
671
594
 
672
595
  /**
@@ -851,34 +774,34 @@ declare function replaceCurrentColor(path: string, color?: string): Promise<stri
851
774
  declare function convertToKebabCase<T extends AnyObject>(obj: T, deep?: boolean): T;
852
775
 
853
776
  /**
854
- * 深度克隆对象,创建完全独立的副本
777
+ * 深拷贝任意 JavaScript 值。
778
+ *
779
+ * - 优先使用原生 `structuredClone`(若可用),覆盖 `Map`/`Set`/`TypedArray`/`ArrayBuffer` 等内建类型。
780
+ * - 对不支持 `structuredClone` 的环境,使用回退实现:
781
+ * - 支持循环引用(`WeakMap` 记忆化)。
782
+ * - 保留原型与属性描述符(含 getter/setter),复制 symbol 键。
783
+ * - 内建类型专项处理:`Date`/`RegExp`/`Map`/`Set`/`ArrayBuffer`/`TypedArray`/`URL`/`Error`。
855
784
  *
856
785
  * @category Object
857
- * @param obj 待克隆的对象
858
- * @returns 深度克隆后的对象
786
+ * @typeParam T 拷贝值的类型
787
+ * @param obj 要被深拷贝的值
788
+ * @param cache 内部使用的 `WeakMap`(循环引用记忆化),一般不需要传入
789
+ * @returns 新的深拷贝值,与输入值结构等价、引用独立
790
+ *
859
791
  * @example
860
792
  * ```ts
861
- * const original = {
862
- * name: 'John',
863
- * age: 30,
864
- * address: {
865
- * city: 'New York',
866
- * zip: '10001'
867
- * },
868
- * hobbies: ['reading', 'coding']
869
- * }
870
- *
871
- * const cloned = deepClone(original)
872
- * cloned.address.city = 'Los Angeles'
873
- * cloned.hobbies.push('gaming')
874
- *
875
- * console.log(original.address.city) // 'New York' (未改变)
876
- * console.log(original.hobbies.length) // 2 (未改变)
877
- * console.log(cloned.address.city) // 'Los Angeles'
878
- * console.log(cloned.hobbies.length) // 3
793
+ * const source = { a: 1, d: new Date(), m: new Map([[1, { x: 2 }]]) }
794
+ * const cloned = deepClone(source)
795
+ * cloned !== source // true
796
+ * cloned.d !== source.d // true
797
+ * cloned.m !== source.m // true
798
+ * cloned.m.get(1) !== source.m.get(1) // true
879
799
  * ```
800
+ *
801
+ * @remarks
802
+ * 若对象包含不可克隆资源(如带有原生句柄的自定义对象),请在外层进行自定义序列化逻辑或为该类型添加专用分支。
880
803
  */
881
- declare function deepClone<T>(obj: T): T;
804
+ declare function deepClone<T>(obj: T, cache?: WeakMap<object, any>): T;
882
805
 
883
806
  /**
884
807
  * 从对象中排除指定的键,返回新对象
@@ -903,139 +826,905 @@ declare function deepClone<T>(obj: T): T;
903
826
  * console.log(basicInfo) // { id: 1, name: 'John' }
904
827
  * ```
905
828
  */
906
- declare function omit<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): OmitByKey<T, K>;
829
+ declare function omit<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): OmitByKey<T, K>;
830
+ /**
831
+ * 从对象中排除值为undefined的键
832
+ *
833
+ * @category Object
834
+ * @param obj 源对象
835
+ * @returns 排除undefined值后的新对象
836
+ * @example
837
+ * ```ts
838
+ * const data = {
839
+ * name: 'John',
840
+ * age: undefined,
841
+ * city: 'New York',
842
+ * country: undefined
843
+ * }
844
+ *
845
+ * const cleaned = omitUndefined(data)
846
+ * console.log(cleaned) // { name: 'John', city: 'New York' }
847
+ *
848
+ * // 用于API请求前清理数据
849
+ * const requestData = omitUndefined({
850
+ * title: 'Post Title',
851
+ * content: 'Post content',
852
+ * tags: undefined,
853
+ * published: true
854
+ * })
855
+ * ```
856
+ */
857
+ declare function omitUndefined<T extends AnyObject>(obj: T): Partial<T>;
858
+
859
+ type PathSegment = string | number;
860
+ type PathSegments = PathSegment[];
861
+ type PathInput = string | PathSegments;
862
+ /**
863
+ * 检查值是否为有效的容器类型(对象或数组)
864
+ *
865
+ * - isObject: 仅检查纯对象,排除数组
866
+ * - isValidContainer: 检查所有可作为容器的类型(对象 + 数组)
867
+ *
868
+ * 支持 Vue 3 的 Proxy 对象和 Proxy 数组。
869
+ *
870
+ * @category Validator
871
+ * @param value - 待检查的值
872
+ * @returns 是否为有效容器(对象或数组)
873
+ * @example
874
+ * ```ts
875
+ * isValidContainer({}) // true
876
+ * isValidContainer([]) // true
877
+ * isValidContainer(new Proxy({}, {})) // true
878
+ * isValidContainer(null) // false
879
+ * isValidContainer('string') // false
880
+ * isValidContainer(123) // false
881
+ * ```
882
+ */
883
+ declare function isValidContainer(value: any): boolean;
884
+ /**
885
+ * 将路径字符串解析为片段数组。
886
+ *
887
+ * - 支持点语法与方括号语法混用
888
+ * - 引号键支持单/双引号与反斜杠转义
889
+ * - 方括号内未引号的非负整数字面量解析为 number 段
890
+ * - 点语法中的纯数字段保持字符串(不转为索引)
891
+ *
892
+ * @category Object
893
+ * @param path 路径字符串或片段数组
894
+ * @returns 解析后的片段数组
895
+ * @example
896
+ * ```ts
897
+ * toPath('a.b[0].c') // ['a', 'b', 0, 'c']
898
+ * toPath("a['x.y']") // ['a', 'x.y']
899
+ * ```
900
+ */
901
+ declare function toPath(path: PathInput): PathSegments;
902
+ /**
903
+ * 读取对象指定路径的值。
904
+ *
905
+ * - 若取值结果为 undefined,则返回 defaultValue
906
+ * - 若取值结果为 null,则直接返回 null(不触发默认值)
907
+ * - 传入空路径时返回 object 本身
908
+ *
909
+ * @category Object
910
+ * @param object 源对象
911
+ * @param path 路径字符串或片段数组
912
+ * @param defaultValue 结果为 undefined 时返回的默认值
913
+ * @returns 读取到的值或默认值
914
+ * @example
915
+ * ```ts
916
+ * const obj = { a: { b: { c: 1, d: undefined }, e: null }, arr: [{ x: 9 }] }
917
+ * getPath(obj, 'a.b.c') // 1
918
+ * getPath(obj, 'a.b.d', 42) // 42(d 为 undefined,使用默认值)
919
+ * getPath(obj, 'a.e', 100) // null(null 不触发默认值)
920
+ * getPath(obj, 'arr[0].x') // 9
921
+ * getPath(obj, '') // 返回 obj 本身
922
+ * ```
923
+ */
924
+ declare function getPath<T, D = undefined>(object: T, path: PathInput, defaultValue?: D): unknown | D;
925
+ /**
926
+ * 在对象指定路径写入值。缺失路径会被自动创建:
927
+ * - 下一段为 number(索引)时创建数组
928
+ * - 下一段为 string(属性)时创建对象
929
+ *
930
+ * 若中途遇到非容器类型(如字符串/数值/布尔),会被替换为正确的容器以继续写入。
931
+ *
932
+ * @category Object
933
+ * @param object 目标对象(原地修改并返回同一引用)
934
+ * @param path 路径字符串或片段数组
935
+ * @param value 要写入的值
936
+ * @returns 原对象(已修改)
937
+ * @example
938
+ * ```ts
939
+ * const obj: any = {}
940
+ * setPath(obj, 'a.b[0].c', 7)
941
+ * // obj => { a: { b: [{ c: 7 }] } }
942
+ *
943
+ * setPath(obj, 'a.b[2].d', 8)
944
+ * // 数组自动扩容到长度 3
945
+ * // obj.a.b[2] => { d: 8 }
946
+ *
947
+ * setPath(obj, 'a.0.b', 1) // 点语法数字键保持为字符串键
948
+ * // obj => { a: { 0: { b: 1 } } }
949
+ * setPath(obj, 'a[0].b', 2) // 索引用方括号
950
+ * // obj.a[0].b => 2
951
+ * ```
952
+ */
953
+ declare function setPath<T extends Record<string, any>>(object: T, path: PathInput, value: unknown): T;
954
+ /**
955
+ * 将片段数组序列化为路径字符串。
956
+ *
957
+ * 规则:
958
+ * - 合法标识符段使用点拼接(a.b.c)
959
+ * - 数字段转为索引([0])
960
+ * - 其它需要转义的键使用方括号引号(['x.y']),并转义 \\ 与 '\''
961
+ *
962
+ * @category Object
963
+ * @param segments 路径片段数组
964
+ * @returns 路径字符串
965
+ * @example
966
+ * ```ts
967
+ * const p = joinPath(['a', 'x.y', 0, 'space key'])
968
+ * // p: "a['x.y'][0]['space key']"
969
+ * // 与解析往返:toPath(p) => ['a', 'x.y', 0, 'space key']
970
+ * ```
971
+ */
972
+ declare function joinPath(segments: (string | number)[]): string;
973
+
974
+ /**
975
+ * 从对象中选择指定的键,返回新对象
976
+ *
977
+ * @category Object
978
+ * @param obj 源对象
979
+ * @param keys 要选择的键数组
980
+ * @returns 只包含指定键的新对象
981
+ * @example
982
+ * ```ts
983
+ * const user = {
984
+ * id: 1,
985
+ * name: 'John',
986
+ * email: 'john@example.com',
987
+ * password: 'secret',
988
+ * createdAt: '2023-01-01',
989
+ * updatedAt: '2023-01-15'
990
+ * }
991
+ *
992
+ * const publicInfo = pick(user, ['id', 'name', 'email'])
993
+ * console.log(publicInfo) // { id: 1, name: 'John', email: 'john@example.com' }
994
+ *
995
+ * const basicInfo = pick(user, ['id', 'name'])
996
+ * console.log(basicInfo) // { id: 1, name: 'John' }
997
+ * ```
998
+ */
999
+ declare function pick<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): PickByKey<T, K>;
1000
+
1001
+ /**
1002
+ * 将对象按指定键分离为两个对象
1003
+ *
1004
+ * @category Object
1005
+ * @param obj 源对象
1006
+ * @param keys 要分离的键数组
1007
+ * @returns 包含picked和omitted两个对象的结果
1008
+ * @example
1009
+ * ```ts
1010
+ * const user = {
1011
+ * id: 1,
1012
+ * name: 'John',
1013
+ * email: 'john@example.com',
1014
+ * password: 'secret',
1015
+ * role: 'admin'
1016
+ * }
1017
+ *
1018
+ * const { picked, omitted } = separate(user, ['id', 'name'])
1019
+ * console.log(picked) // { id: 1, name: 'John' }
1020
+ * console.log(omitted) // { email: 'john@example.com', password: 'secret', role: 'admin' }
1021
+ *
1022
+ * // 用于分离敏感信息
1023
+ * const { picked: publicData, omitted: privateData } = separate(user, ['id', 'name', 'email'])
1024
+ * ```
1025
+ */
1026
+ declare function separate<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): {
1027
+ picked: PickByKey<T, K>;
1028
+ omitted: OmitByKey<T, K>;
1029
+ };
1030
+ /**
1031
+ * 将对象按多分组键集合进行分离(浅层),返回各分组与 others
1032
+ *
1033
+ * - 键冲突策略:先到先得。若同一键出现在多个分组中,则归入第一个匹配到的分组
1034
+ * - 仅处理对象自有的浅层键,不解析深层路径
1035
+ * - 分组中包含不存在于对象的键将被忽略
1036
+ *
1037
+ * @category Object
1038
+ * @param obj 源对象
1039
+ * @param groups 分组映射,如 { a: ['x', 'y'], b: ['z'] }
1040
+ * @returns 一个对象,包含每个分组的子对象以及 others(其余未被分组捕获的键)
1041
+ * @example
1042
+ * ```ts
1043
+ * const options = { id: 1, name: 'John', email: 'a@b.com', role: 'admin' }
1044
+ * const { a, b, others } = separateMany(options, { a: ['id'], b: ['name'] as const })
1045
+ * // a: { id: 1 }
1046
+ * // b: { name: 'John' }
1047
+ * // others: { email: 'a@b.com', role: 'admin' }
1048
+ * ```
1049
+ */
1050
+ declare function separateMany<T extends AnyObject, M extends Record<string, readonly (keyof T)[]>>(obj: T, groups: M): {
1051
+ [P in keyof M]: PickByKey<T, M[P][number]>;
1052
+ } & {
1053
+ others: OmitByKey<T, M[keyof M][number]>;
1054
+ };
1055
+
1056
+ /**
1057
+ * 将字符串转换为Start Case格式(每个单词首字母大写,用空格分隔)。
1058
+ *
1059
+ * @category String
1060
+ * @param str 要转换的字符串
1061
+ * @returns Start Case格式的字符串
1062
+ * @example
1063
+ * ```ts
1064
+ * startCase('firstName') // 'First Name'
1065
+ * startCase('first_name') // 'First Name'
1066
+ * startCase('first-name') // 'First Name'
1067
+ * startCase('XMLHttpRequest') // 'XML Http Request'
1068
+ * ```
1069
+ */
1070
+ declare function startCase(str: string): string;
1071
+ /**
1072
+ * 将字符串转换为驼峰命名格式(第一个单词小写,后续单词首字母大写)。
1073
+ *
1074
+ * @category String
1075
+ * @param str 要转换的字符串
1076
+ * @returns 驼峰命名格式的字符串
1077
+ * @example
1078
+ * ```ts
1079
+ * camelCase('First Name') // 'firstName'
1080
+ * camelCase('first_name') // 'firstName'
1081
+ * camelCase('first-name') // 'firstName'
1082
+ * camelCase('XMLHttpRequest') // 'xmlHttpRequest'
1083
+ * ```
1084
+ */
1085
+ declare function camelCase(str: string): string;
1086
+ /**
1087
+ * 将字符串转换为短横线命名格式(kebab-case)。
1088
+ *
1089
+ * @category String
1090
+ * @param str 要转换的字符串
1091
+ * @returns 短横线命名格式的字符串
1092
+ * @example
1093
+ * ```ts
1094
+ * kebabCase('firstName') // 'first-name'
1095
+ * kebabCase('First Name') // 'first-name'
1096
+ * kebabCase('first_name') // 'first-name'
1097
+ * kebabCase('XMLHttpRequest') // 'xml-http-request'
1098
+ * ```
1099
+ */
1100
+ declare function kebabCase(str: string): string;
1101
+ /**
1102
+ * 将字符串转换为下划线命名格式(snake_case)。
1103
+ *
1104
+ * @category String
1105
+ * @param str 要转换的字符串
1106
+ * @returns 下划线命名格式的字符串
1107
+ * @example
1108
+ * ```ts
1109
+ * snakeCase('firstName') // 'first_name'
1110
+ * snakeCase('First Name') // 'first_name'
1111
+ * snakeCase('first-name') // 'first_name'
1112
+ * snakeCase('XMLHttpRequest') // 'xml_http_request'
1113
+ * ```
1114
+ */
1115
+ declare function snakeCase(str: string): string;
1116
+ /**
1117
+ * 将字符串转换为帕斯卡命名格式(PascalCase,每个单词首字母大写)。
1118
+ *
1119
+ * @category String
1120
+ * @param str 要转换的字符串
1121
+ * @returns 帕斯卡命名格式的字符串
1122
+ * @example
1123
+ * ```ts
1124
+ * pascalCase('firstName') // 'FirstName'
1125
+ * pascalCase('first_name') // 'FirstName'
1126
+ * pascalCase('first-name') // 'FirstName'
1127
+ * pascalCase('XMLHttpRequest') // 'XmlHttpRequest'
1128
+ * ```
1129
+ */
1130
+ declare function pascalCase(str: string): string;
1131
+ /**
1132
+ * 将字符串首字母大写,其余字母小写。
1133
+ *
1134
+ * @category String
1135
+ * @param str 要转换的字符串
1136
+ * @returns 首字母大写的字符串
1137
+ * @example
1138
+ * ```ts
1139
+ * capitalize('hello') // 'Hello'
1140
+ * capitalize('HELLO') // 'Hello'
1141
+ * capitalize('hello world') // 'Hello world'
1142
+ * ```
1143
+ */
1144
+ declare function capitalize(str: string): string;
1145
+ /**
1146
+ * 将字符串首字母大写,其余字母保持原样。
1147
+ *
1148
+ * @category String
1149
+ * @param str 要转换的字符串
1150
+ * @returns 首字母大写的字符串
1151
+ * @example
1152
+ * ```ts
1153
+ * upperFirst('hello') // 'Hello'
1154
+ * upperFirst('hELLO') // 'HELLO'
1155
+ * upperFirst('hello world') // 'Hello world'
1156
+ * ```
1157
+ */
1158
+ declare function upperFirst(str: string): string;
1159
+ /**
1160
+ * 将字符串首字母小写,其余字母保持原样。
1161
+ *
1162
+ * @category String
1163
+ * @param str 要转换的字符串
1164
+ * @returns 首字母小写的字符串
1165
+ * @example
1166
+ * ```ts
1167
+ * lowerFirst('Hello') // 'hello'
1168
+ * lowerFirst('HELLO') // 'hELLO'
1169
+ * lowerFirst('Hello World') // 'hello World'
1170
+ * ```
1171
+ */
1172
+ declare function lowerFirst(str: string): string;
907
1173
  /**
908
- * 从对象中排除值为undefined的键
1174
+ * 将字符串转换为大写格式,单词之间用空格分隔。
909
1175
  *
910
- * @category Object
911
- * @param obj 源对象
912
- * @returns 排除undefined值后的新对象
1176
+ * @category String
1177
+ * @param str 要转换的字符串
1178
+ * @returns 大写格式的字符串
913
1179
  * @example
914
1180
  * ```ts
915
- * const data = {
916
- * name: 'John',
917
- * age: undefined,
918
- * city: 'New York',
919
- * country: undefined
920
- * }
1181
+ * upperCase('firstName') // 'FIRST NAME'
1182
+ * upperCase('first_name') // 'FIRST NAME'
1183
+ * upperCase('first-name') // 'FIRST NAME'
1184
+ * upperCase('XMLHttpRequest') // 'XML HTTP REQUEST'
1185
+ * ```
1186
+ */
1187
+ declare function upperCase(str: string): string;
1188
+ /**
1189
+ * 将字符串转换为小写格式,单词之间用空格分隔。
921
1190
  *
922
- * const cleaned = omitUndefined(data)
923
- * console.log(cleaned) // { name: 'John', city: 'New York' }
1191
+ * @category String
1192
+ * @param str 要转换的字符串
1193
+ * @returns 小写格式的字符串
1194
+ * @example
1195
+ * ```ts
1196
+ * lowerCase('firstName') // 'first name'
1197
+ * lowerCase('First_Name') // 'first name'
1198
+ * lowerCase('FIRST-NAME') // 'first name'
1199
+ * lowerCase('XMLHttpRequest') // 'xml http request'
1200
+ * ```
1201
+ */
1202
+ declare function lowerCase(str: string): string;
1203
+ /**
1204
+ * 将驼峰命名转换为kebab-case
1205
+ * @deprecated Use `kebabCase` instead
1206
+ */
1207
+ declare const camelToKebab: typeof kebabCase;
1208
+ /**
1209
+ * 将kebab-case转换为驼峰命名
1210
+ * @deprecated Use `camelCase` instead
1211
+ */
1212
+ declare const kebabToCamel: typeof camelCase;
1213
+
1214
+ /**
1215
+ * 将字符串分解为单词数组。支持camelCase、snake_case、kebab-case等各种命名风格。
924
1216
  *
925
- * // 用于API请求前清理数据
926
- * const requestData = omitUndefined({
927
- * title: 'Post Title',
928
- * content: 'Post content',
929
- * tags: undefined,
930
- * published: true
931
- * })
1217
+ * @category String
1218
+ * @param str 要分解的字符串
1219
+ * @returns 单词数组
1220
+ * @example
1221
+ * ```ts
1222
+ * words('helloWorld') // ['hello', 'World']
1223
+ * words('hello_world') // ['hello', 'world']
1224
+ * words('hello-world') // ['hello', 'world']
1225
+ * words('XMLHttpRequest') // ['XML', 'Http', 'Request']
932
1226
  * ```
933
1227
  */
934
- declare function omitUndefined<T extends AnyObject>(obj: T): Partial<T>;
1228
+ declare function words(str: string): string[];
935
1229
 
936
1230
  /**
937
- * 从对象中选择指定的键,返回新对象
1231
+ * 树节点类型定义
1232
+ *
1233
+ * @template T 节点数据类型
1234
+ */
1235
+ type TreeNode<T = any> = T & {
1236
+ children?: TreeNode<T>[];
1237
+ [key: string]: any;
1238
+ };
1239
+ declare const TreeConfigSchema: z.ZodObject<{
1240
+ id: z.ZodDefault<z.ZodString>;
1241
+ pid: z.ZodDefault<z.ZodString>;
1242
+ children: z.ZodDefault<z.ZodString>;
1243
+ }, z.core.$strip>;
1244
+ /**
1245
+ * 树形配置输入类型
1246
+ */
1247
+ type TreeConfigInput = z.input<typeof TreeConfigSchema>;
1248
+ declare const _TreeStatsSchema: z.ZodObject<{
1249
+ total: z.ZodNumber;
1250
+ leaves: z.ZodNumber;
1251
+ depth: z.ZodNumber;
1252
+ branches: z.ZodNumber;
1253
+ }, z.core.$strip>;
1254
+ /**
1255
+ * 树统计信息类型
1256
+ */
1257
+ type TreeStats = z.infer<typeof _TreeStatsSchema>;
1258
+ /**
1259
+ * 树节点谓词函数类型
1260
+ *
1261
+ * @template T 节点数据类型
1262
+ * @param params 包含节点信息的对象参数
1263
+ * @param params.node 当前节点
1264
+ * @param params.depth 节点深度(从0开始)
1265
+ * @param params.path 从根节点到当前节点的路径数组
1266
+ * @param params.index 节点在同级节点中的索引
1267
+ * @returns 是否满足条件
1268
+ */
1269
+ type TreePredicate<T = any> = (params: {
1270
+ node: TreeNode<T>;
1271
+ depth: number;
1272
+ path: readonly TreeNode<T>[];
1273
+ index: number;
1274
+ }) => boolean;
1275
+ /**
1276
+ * 树节点转换函数类型
1277
+ *
1278
+ * @template T 源节点数据类型
1279
+ * @template R 目标节点数据类型
1280
+ * @param params 包含节点信息的对象参数
1281
+ * @param params.node 当前节点
1282
+ * @param params.depth 节点深度(从0开始)
1283
+ * @param params.path 从根节点到当前节点的路径数组
1284
+ * @param params.index 节点在同级节点中的索引
1285
+ * @returns 转换后的节点数据
1286
+ */
1287
+ type TreeTransformer<T = any, R = any> = (params: {
1288
+ node: TreeNode<T>;
1289
+ depth: number;
1290
+ path: readonly TreeNode<T>[];
1291
+ index: number;
1292
+ }) => R;
1293
+ /**
1294
+ * 树节点访问函数类型
1295
+ *
1296
+ * @template T 节点数据类型
1297
+ * @param params 包含节点信息的对象参数
1298
+ * @param params.node 当前节点
1299
+ * @param params.depth 节点深度(从0开始)
1300
+ * @param params.path 从根节点到当前节点的路径数组
1301
+ * @param params.index 节点在同级节点中的索引
1302
+ * @returns 返回false可以终止遍历或跳过子节点
1303
+ */
1304
+ type TreeVisitor<T = any> = (params: {
1305
+ node: TreeNode<T>;
1306
+ depth: number;
1307
+ path: readonly TreeNode<T>[];
1308
+ index: number;
1309
+ }) => void | boolean;
1310
+ /**
1311
+ * 树形数据结构操作工具类
1312
+ *
1313
+ * 提供了一系列操作树形数据的静态方法,包括:
1314
+ * - 查找:find, findAll, findById
1315
+ * - 转换:fromList, toList, transform
1316
+ * - 过滤:filter
1317
+ * - 遍历:forEach
1318
+ * - 统计:estimateSize, getStats
1319
+ * - 修改:insertBefore, insertAfter, remove
1320
+ * - 验证:validate
1321
+ *
1322
+ * 所有使用谓词函数或访问函数的方法都采用对象解构参数格式:
1323
+ * `({ node, depth, path, index }) => boolean`
938
1324
  *
939
- * @category Object
940
- * @param obj 源对象
941
- * @param keys 要选择的键数组
942
- * @returns 只包含指定键的新对象
943
1325
  * @example
944
1326
  * ```ts
945
- * const user = {
946
- * id: 1,
947
- * name: 'John',
948
- * email: 'john@example.com',
949
- * password: 'secret',
950
- * createdAt: '2023-01-01',
951
- * updatedAt: '2023-01-15'
952
- * }
1327
+ * const tree = [
1328
+ * {
1329
+ * id: '1',
1330
+ * name: '根节点',
1331
+ * children: [
1332
+ * { id: '2', name: '子节点1', children: [] },
1333
+ * { id: '3', name: '子节点2', children: [] }
1334
+ * ]
1335
+ * }
1336
+ * ]
953
1337
  *
954
- * const publicInfo = pick(user, ['id', 'name', 'email'])
955
- * console.log(publicInfo) // { id: 1, name: 'John', email: 'john@example.com' }
1338
+ * // 查找节点
1339
+ * const node = Tree.find(tree, ({ node }) => node.name === '子节点1')
956
1340
  *
957
- * const basicInfo = pick(user, ['id', 'name'])
958
- * console.log(basicInfo) // { id: 1, name: 'John' }
1341
+ * // 遍历所有节点
1342
+ * Tree.forEach(tree, ({ node, depth }) => {
1343
+ * console.log(`${' '.repeat(depth)}${node.name}`)
1344
+ * })
1345
+ *
1346
+ * // 转换节点结构
1347
+ * const transformed = Tree.transform(tree, ({ node, depth }) => ({
1348
+ * key: node.id,
1349
+ * title: node.name,
1350
+ * level: depth
1351
+ * }))
959
1352
  * ```
960
1353
  */
961
- declare function pick<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): PickByKey<T, K>;
962
-
963
- interface SeparateResult<T extends AnyObject, K extends keyof T> {
964
- picked: PickByKey<T, K>;
965
- omitted: OmitByKey<T, K>;
1354
+ declare class Tree {
1355
+ private static dfsGenerator;
1356
+ private static bfsGenerator;
1357
+ private static selectStrategy;
1358
+ /**
1359
+ * 从扁平数组创建树形结构
1360
+ *
1361
+ * @category Data Structures
1362
+ * @param list 扁平数组数据
1363
+ * @param config 树形配置选项
1364
+ * @returns 树形结构数组
1365
+ * @example
1366
+ * ```ts
1367
+ * const flatData = [
1368
+ * { id: '1', name: '部门1', parentId: null },
1369
+ * { id: '2', name: '部门1-1', parentId: '1' },
1370
+ * { id: '3', name: '部门1-2', parentId: '1' },
1371
+ * { id: '4', name: '部门1-1-1', parentId: '2' }
1372
+ * ]
1373
+ *
1374
+ * const tree = Tree.fromList(flatData, {
1375
+ * id: 'id',
1376
+ * pid: 'parentId',
1377
+ * children: 'children'
1378
+ * })
1379
+ *
1380
+ * console.log(tree) // 转换为树形结构
1381
+ * ```
1382
+ */
1383
+ static fromList<T = any>(list: T[], config?: TreeConfigInput): TreeNode<T>[];
1384
+ /**
1385
+ * 将树形结构转换为扁平数组
1386
+ *
1387
+ * @category Data Structures
1388
+ * @param tree 树形结构(单个节点或节点数组)
1389
+ * @param config 树形配置选项
1390
+ * @returns 扁平数组
1391
+ * @example
1392
+ * ```ts
1393
+ * const tree = [
1394
+ * {
1395
+ * id: '1',
1396
+ * name: '根节点',
1397
+ * children: [
1398
+ * { id: '2', name: '子节点1', children: [] },
1399
+ * { id: '3', name: '子节点2', children: [] }
1400
+ * ]
1401
+ * }
1402
+ * ]
1403
+ *
1404
+ * const flatList = Tree.toList(tree)
1405
+ * console.log(flatList) // [{ id: '1', name: '根节点' }, { id: '2', name: '子节点1' }, ...]
1406
+ * ```
1407
+ */
1408
+ static toList<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): T[];
1409
+ /**
1410
+ * 估算树形结构的节点数量
1411
+ *
1412
+ * @category Data Structures
1413
+ * @param tree 树形结构(单个节点或节点数组)
1414
+ * @param config 树形配置选项
1415
+ * @returns 节点总数量
1416
+ * @example
1417
+ * ```ts
1418
+ * const tree = [
1419
+ * {
1420
+ * id: '1',
1421
+ * name: '根节点',
1422
+ * children: [
1423
+ * { id: '2', name: '子节点1', children: [] },
1424
+ * { id: '3', name: '子节点2', children: [] }
1425
+ * ]
1426
+ * }
1427
+ * ]
1428
+ *
1429
+ * const size = Tree.estimateSize(tree)
1430
+ * console.log(size) // 3
1431
+ * ```
1432
+ */
1433
+ static estimateSize<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): number;
1434
+ /**
1435
+ * 查找树中第一个满足条件的节点
1436
+ *
1437
+ * @category Data Structures
1438
+ * @param tree 树形结构(单个节点或节点数组)
1439
+ * @param predicate 查找条件函数
1440
+ * @param config 树形配置选项
1441
+ * @returns 匹配的节点;未找到时返回undefined
1442
+ * @example
1443
+ * ```ts
1444
+ * const tree = [
1445
+ * {
1446
+ * id: '1',
1447
+ * name: '部门1',
1448
+ * children: [
1449
+ * { id: '2', name: '部门1-1', children: [] }
1450
+ * ]
1451
+ * }
1452
+ * ]
1453
+ *
1454
+ * const result = Tree.find(tree, ({ node }) => node.name === '部门1-1')
1455
+ * console.log(result?.id) // '2'
1456
+ * ```
1457
+ */
1458
+ static find<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNode<T> | undefined;
1459
+ /**
1460
+ * 查找树中所有满足条件的节点
1461
+ *
1462
+ * @category Data Structures
1463
+ * @param tree 树形结构(单个节点或节点数组)
1464
+ * @param predicate 查找条件函数
1465
+ * @param config 树形配置选项
1466
+ * @returns 所有匹配的节点数组
1467
+ * @example
1468
+ * ```ts
1469
+ * const tree = [
1470
+ * {
1471
+ * id: '1',
1472
+ * type: 'folder',
1473
+ * name: '根目录',
1474
+ * children: [
1475
+ * { id: '2', type: 'file', name: '文件1', children: [] },
1476
+ * { id: '3', type: 'file', name: '文件2', children: [] }
1477
+ * ]
1478
+ * }
1479
+ * ]
1480
+ *
1481
+ * const files = Tree.findAll(tree, ({ node }) => node.type === 'file')
1482
+ * console.log(files.length) // 2
1483
+ * ```
1484
+ */
1485
+ static findAll<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNode<T>[];
1486
+ /**
1487
+ * 根据ID查找树中的节点
1488
+ *
1489
+ * @category Data Structures
1490
+ * @param tree 树形结构(单个节点或节点数组)
1491
+ * @param id 要查找的节点ID
1492
+ * @param config 树形配置选项
1493
+ * @returns 匹配的节点;未找到时返回undefined
1494
+ * @example
1495
+ * ```ts
1496
+ * const tree = [
1497
+ * {
1498
+ * id: '1',
1499
+ * name: '根节点',
1500
+ * children: [
1501
+ * { id: '2', name: '子节点', children: [] }
1502
+ * ]
1503
+ * }
1504
+ * ]
1505
+ *
1506
+ * const result = Tree.findById(tree, '2')
1507
+ * console.log(result?.name) // '子节点'
1508
+ * ```
1509
+ */
1510
+ static findById<T = any>(tree: TreeNode<T> | TreeNode<T>[], id: string, config?: TreeConfigInput): TreeNode<T> | undefined;
1511
+ /**
1512
+ * 获取树形结构的统计信息
1513
+ *
1514
+ * @category Data Structures
1515
+ * @param tree 树形结构(单个节点或节点数组)
1516
+ * @param config 树形配置选项
1517
+ * @returns 树的统计信息,包含总节点数、叶子节点数、最大深度和分支节点数
1518
+ * @example
1519
+ * ```ts
1520
+ * const tree = [
1521
+ * {
1522
+ * id: '1',
1523
+ * name: '根节点',
1524
+ * children: [
1525
+ * { id: '2', name: '子节点1', children: [] },
1526
+ * { id: '3', name: '子节点2', children: [
1527
+ * { id: '4', name: '孙节点', children: [] }
1528
+ * ] }
1529
+ * ]
1530
+ * }
1531
+ * ]
1532
+ *
1533
+ * const stats = Tree.getStats(tree)
1534
+ * console.log(stats) // { total: 4, leaves: 2, depth: 3, branches: 2 }
1535
+ * ```
1536
+ */
1537
+ static getStats<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): TreeStats;
1538
+ /**
1539
+ * 过滤树形结构,保留满足条件的节点及其祖先和后代
1540
+ *
1541
+ * @category Data Structures
1542
+ * @param tree 树形结构(单个节点或节点数组)
1543
+ * @param predicate 过滤条件函数,接收对象参数 {node, depth, path, index}
1544
+ * @param config 树形配置选项
1545
+ * @returns 过滤后的树形结构数组
1546
+ * @example
1547
+ * ```ts
1548
+ * const tree = [
1549
+ * {
1550
+ * id: '1',
1551
+ * type: 'folder',
1552
+ * name: '根目录',
1553
+ * children: [
1554
+ * { id: '2', type: 'file', name: '文档.txt', children: [] },
1555
+ * { id: '3', type: 'folder', name: '子目录', children: [
1556
+ * { id: '4', type: 'file', name: '图片.jpg', children: [] }
1557
+ * ] }
1558
+ * ]
1559
+ * }
1560
+ * ]
1561
+ *
1562
+ * const filtered = Tree.filter(tree, ({ node }) => node.type === 'file')
1563
+ * // 返回包含所有文件节点及其父级路径的树结构
1564
+ * ```
1565
+ */
1566
+ static filter<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNode<T>[];
1567
+ /**
1568
+ * 转换树形结构,将每个节点转换为新的结构
1569
+ *
1570
+ * @category Data Structures
1571
+ * @param tree 树形结构(单个节点或节点数组)
1572
+ * @param transformer 节点转换函数,接收对象参数 {node, depth, path, index}
1573
+ * @param config 树形配置选项
1574
+ * @returns 转换后的树形结构数组
1575
+ * @example
1576
+ * ```ts
1577
+ * const tree = [
1578
+ * {
1579
+ * id: '1',
1580
+ * name: '部门1',
1581
+ * children: [
1582
+ * { id: '2', name: '部门1-1', children: [] }
1583
+ * ]
1584
+ * }
1585
+ * ]
1586
+ *
1587
+ * const transformed = Tree.transform(tree, ({ node, depth }) => ({
1588
+ * key: node.id,
1589
+ * title: node.name,
1590
+ * level: depth
1591
+ * }))
1592
+ * // 转换为新的数据结构
1593
+ * ```
1594
+ */
1595
+ static transform<T = any, R = any>(tree: TreeNode<T> | TreeNode<T>[], transformer: TreeTransformer<T, R>, config?: TreeConfigInput): TreeNode<R>[];
1596
+ /**
1597
+ * 遍历树形结构的每个节点
1598
+ *
1599
+ * @category Data Structures
1600
+ * @param tree 树形结构(单个节点或节点数组)
1601
+ * @param visitor 访问者函数,接收对象参数 {node, depth, path, index},返回false可以跳过子节点的遍历
1602
+ * @param config 树形配置选项
1603
+ * @example
1604
+ * ```ts
1605
+ * const tree = [
1606
+ * {
1607
+ * id: '1',
1608
+ * name: '根节点',
1609
+ * children: [
1610
+ * { id: '2', name: '子节点', children: [] }
1611
+ * ]
1612
+ * }
1613
+ * ]
1614
+ *
1615
+ * Tree.forEach(tree, ({ node, depth }) => {
1616
+ * console.log(`${' '.repeat(depth * 2)}${node.name}`)
1617
+ * // 输出缩进的树结构
1618
+ * })
1619
+ * ```
1620
+ */
1621
+ static forEach<T = any>(tree: TreeNode<T> | TreeNode<T>[], visitor: TreeVisitor<T>, config?: TreeConfigInput): void;
1622
+ /**
1623
+ * 在指定节点前插入新节点
1624
+ *
1625
+ * @category Data Structures
1626
+ * @param tree 树形结构数组
1627
+ * @param targetId 目标节点的ID
1628
+ * @param newNode 要插入的新节点数据
1629
+ * @param config 树形配置选项
1630
+ * @returns 是否成功插入
1631
+ * @example
1632
+ * ```ts
1633
+ * const tree = [
1634
+ * {
1635
+ * id: '1',
1636
+ * name: '节点1',
1637
+ * children: [
1638
+ * { id: '2', name: '节点2', children: [] }
1639
+ * ]
1640
+ * }
1641
+ * ]
1642
+ *
1643
+ * const success = Tree.insertBefore(tree, '2', { id: '1.5', name: '新节点' })
1644
+ * console.log(success) // true
1645
+ * ```
1646
+ */
1647
+ static insertBefore<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
1648
+ /**
1649
+ * 在指定节点后插入新节点
1650
+ *
1651
+ * @category Data Structures
1652
+ * @param tree 树形结构数组
1653
+ * @param targetId 目标节点的ID
1654
+ * @param newNode 要插入的新节点数据
1655
+ * @param config 树形配置选项
1656
+ * @returns 是否成功插入
1657
+ * @example
1658
+ * ```ts
1659
+ * const tree = [
1660
+ * {
1661
+ * id: '1',
1662
+ * name: '节点1',
1663
+ * children: [
1664
+ * { id: '2', name: '节点2', children: [] }
1665
+ * ]
1666
+ * }
1667
+ * ]
1668
+ *
1669
+ * const success = Tree.insertAfter(tree, '2', { id: '3', name: '新节点' })
1670
+ * console.log(success) // true
1671
+ * ```
1672
+ */
1673
+ static insertAfter<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
1674
+ /**
1675
+ * 从树中删除指定节点
1676
+ *
1677
+ * @category Data Structures
1678
+ * @param tree 树形结构数组
1679
+ * @param targetId 要删除的节点ID
1680
+ * @param config 树形配置选项
1681
+ * @returns 被删除的节点,未找到时返回undefined
1682
+ * @example
1683
+ * ```ts
1684
+ * const tree = [
1685
+ * {
1686
+ * id: '1',
1687
+ * name: '根节点',
1688
+ * children: [
1689
+ * { id: '2', name: '子节点', children: [] }
1690
+ * ]
1691
+ * }
1692
+ * ]
1693
+ *
1694
+ * const removed = Tree.remove(tree, '2')
1695
+ * console.log(removed?.name) // '子节点'
1696
+ * ```
1697
+ */
1698
+ static remove<T = any>(tree: TreeNode<T>[], targetId: string, config?: TreeConfigInput): TreeNode<T> | undefined;
1699
+ /**
1700
+ * 验证树形结构的有效性
1701
+ *
1702
+ * @category Data Structures
1703
+ * @param tree 树形结构(单个节点或节点数组)
1704
+ * @param config 树形配置选项
1705
+ * @returns 验证结果,包含是否有效和错误信息数组
1706
+ * @example
1707
+ * ```ts
1708
+ * const tree = [
1709
+ * {
1710
+ * id: '1',
1711
+ * name: '根节点',
1712
+ * children: [
1713
+ * { id: '2', name: '子节点', children: [] }
1714
+ * ]
1715
+ * }
1716
+ * ]
1717
+ *
1718
+ * const result = Tree.validate(tree)
1719
+ * console.log(result.isValid) // true
1720
+ * console.log(result.errors) // []
1721
+ * ```
1722
+ */
1723
+ static validate<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): {
1724
+ isValid: boolean;
1725
+ errors: string[];
1726
+ };
966
1727
  }
967
- /**
968
- * 将对象按指定键分离为两个对象
969
- *
970
- * @category Object
971
- * @param obj 源对象
972
- * @param keys 要分离的键数组
973
- * @returns 包含picked和omitted两个对象的结果
974
- * @example
975
- * ```ts
976
- * const user = {
977
- * id: 1,
978
- * name: 'John',
979
- * email: 'john@example.com',
980
- * password: 'secret',
981
- * role: 'admin'
982
- * }
983
- *
984
- * const { picked, omitted } = separate(user, ['id', 'name'])
985
- * console.log(picked) // { id: 1, name: 'John' }
986
- * console.log(omitted) // { email: 'john@example.com', password: 'secret', role: 'admin' }
987
- *
988
- * // 用于分离敏感信息
989
- * const { picked: publicData, omitted: privateData } = separate(user, ['id', 'name', 'email'])
990
- * ```
991
- */
992
- declare function separate<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): SeparateResult<T, K>;
993
-
994
- /**
995
- * 将字符串首字母大写
996
- *
997
- * @category String
998
- * @param str 待处理的字符串
999
- * @returns 首字母大写的字符串
1000
- * @example
1001
- * ```ts
1002
- * console.log(capitalize('hello')) // 'Hello'
1003
- * console.log(capitalize('WORLD')) // 'WORLD'
1004
- * console.log(capitalize('')) // ''
1005
- * console.log(capitalize('a')) // 'A'
1006
- * ```
1007
- */
1008
- declare function capitalize(str: string): string;
1009
- /**
1010
- * 将驼峰命名转换为kebab-case
1011
- *
1012
- * @category String
1013
- * @param str 驼峰命名的字符串
1014
- * @returns kebab-case格式的字符串
1015
- * @example
1016
- * ```ts
1017
- * console.log(camelToKebab('helloWorld')) // 'hello-world'
1018
- * console.log(camelToKebab('firstName')) // 'first-name'
1019
- * console.log(camelToKebab('XMLHttpRequest')) // 'x-m-l-http-request'
1020
- * console.log(camelToKebab('hello')) // 'hello'
1021
- * ```
1022
- */
1023
- declare function camelToKebab(str: string): string;
1024
- /**
1025
- * 将kebab-case转换为驼峰命名
1026
- *
1027
- * @category String
1028
- * @param str kebab-case格式的字符串
1029
- * @returns 驼峰命名的字符串
1030
- * @example
1031
- * ```ts
1032
- * console.log(kebabToCamel('hello-world')) // 'helloWorld'
1033
- * console.log(kebabToCamel('first-name')) // 'firstName'
1034
- * console.log(kebabToCamel('background-color')) // 'backgroundColor'
1035
- * console.log(kebabToCamel('hello')) // 'hello'
1036
- * ```
1037
- */
1038
- declare function kebabToCamel(str: string): string;
1039
1728
 
1040
1729
  /**
1041
1730
  * 生成字符串的简单哈希值
@@ -1171,6 +1860,21 @@ declare function isFunction(value: any): value is (...args: any[]) => any;
1171
1860
  * ```
1172
1861
  */
1173
1862
  declare function isEmpty(value: any): boolean;
1863
+ /**
1864
+ * 判断值是否为纯对象(不包括数组、函数、日期等)
1865
+ *
1866
+ * @category Object
1867
+ * @param value 要检查的值
1868
+ * @returns 是否为纯对象
1869
+ * @example
1870
+ * ```ts
1871
+ * isPlainObject({}) // true
1872
+ * isPlainObject([]) // false
1873
+ * isPlainObject(new Date()) // false
1874
+ * isPlainObject(() => {}) // false
1875
+ * ```
1876
+ */
1877
+ declare function isPlainObject(value: unknown): value is Record<string, any>;
1174
1878
 
1175
- export { StorageTypeSchema, Tree, camelToKebab, capitalize, chunk, convertSvgToPng, convertToKebabCase, createStorageConfigSchema, debounce, deepClone, extractFilename, flatten, formatFileSize, getRandomUUID, isArray, isEmpty, isFunction, isNumber, isObject, isString, kebabToCamel, omit, omitUndefined, pick, replaceCurrentColor, separate, simpleHash, sleep, sleepWithCancel, throttle, triggerDownload, unique, useAppStorage, useCopyCode };
1176
- export type { AnyObject, AppStorageReturn, DeepPartial, FirstParam, FirstParameter, GetObjectField, MutableByKeys, OmitByKey, PartialByKeys, PickByKey, ReadonlyByKeys, RenameKeys, RequiredByKeys, StorageConfig, StorageConfigInput, StorageType, StringOrVNode, UnionToIntersection };
1879
+ export { StorageTypeSchema, Tree, camelCase, camelToKebab, capitalize, chunk, convertSvgToPng, convertToKebabCase, createStorageConfigSchema, debounce, deepClone, extractFilename, flatten, formatFileSize, getPath, getRandomUUID, isArray, isEmpty, isFunction, isNumber, isObject, isPlainObject, isString, isValidContainer, joinPath, kebabCase, kebabToCamel, lowerCase, lowerFirst, omit, omitUndefined, pascalCase, pick, replaceCurrentColor, separate, separateMany, setPath, simpleHash, sleep, sleepWithCancel, snakeCase, startCase, throttle, toPath, triggerDownload, unique, upperCase, upperFirst, useAppStorage, useCopyCode, words };
1880
+ export type { AnyObject, ApiAwaitable, ApiAwaitedReturn, ApiUnwrapPromise, AppStorageReturn, ArrayFieldKeys, ComponentAttrs, ComponentEmit, ComponentExposed, ComponentProps, ComponentSlots, ComponentType, DeepPartial, FirstParam, FirstParameter, GetFieldValue, GetObjectField, IsComponent, IsPlainObject, Merge, MutableByKeys, NestedKeys, NonObjectFieldKeys, ObjectFieldKeys, OmitByKey, PartialByKeys, PickByKey, ReactiveValue, ReadonlyByKeys, RenameKeys, RequiredByKeys, StorageConfig, StorageConfigInput, StorageType, StringOrVNode, StripNullable, Suggest, UnionToIntersection, UnknownObject };