@movk/core 0.0.5 → 1.0.1

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.ts CHANGED
@@ -1,4 +1,4 @@
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
4
  /**
@@ -29,6 +29,37 @@ type ApiUnwrapPromise<T> = T extends Promise<infer U> ? U : T;
29
29
  */
30
30
  type ApiAwaitedReturn<TFn> = TFn extends (...args: any[]) => ApiAwaitable<infer R> ? R : never;
31
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
+
32
63
  type UnknownObject = Record<string, unknown>;
33
64
  type AnyObject = Record<string, any>;
34
65
  /**
@@ -176,6 +207,125 @@ type GetObjectField<MaybeObject, Key extends string> = MaybeObject extends Recor
176
207
  * // - () => h('div', '标题') 的惰性渲染函数
177
208
  */
178
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;
179
329
 
180
330
  declare const StorageTypeSchema: z.ZodEnum<{
181
331
  localStorage: "localStorage";
@@ -201,6 +351,38 @@ interface AppStorageReturn<T> {
201
351
  removeItem: () => void;
202
352
  }
203
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
+
204
386
  /**
205
387
  * 应用存储管理的组合式函数,支持localStorage和sessionStorage
206
388
  *
@@ -284,532 +466,130 @@ declare function useAppStorage<T = unknown>(config: StorageConfigInput<T>): AppS
284
466
  */
285
467
  declare function useCopyCode(text: string): Promise<boolean>;
286
468
 
287
- type TreeNode<T = any> = T & {
288
- children?: TreeNode<T>[];
289
- [key: string]: any;
290
- };
291
- declare const TreeConfigSchema: z.ZodObject<{
292
- id: z.ZodDefault<z.ZodString>;
293
- pid: z.ZodDefault<z.ZodString>;
294
- children: z.ZodDefault<z.ZodString>;
295
- }, z.core.$strip>;
296
- type TreeConfigInput = z.input<typeof TreeConfigSchema>;
297
- declare const _TreeStatsSchema: z.ZodObject<{
298
- total: z.ZodNumber;
299
- leaves: z.ZodNumber;
300
- depth: z.ZodNumber;
301
- branches: z.ZodNumber;
302
- }, z.core.$strip>;
303
- type TreeStats = z.infer<typeof _TreeStatsSchema>;
304
- interface TreeNodeResult<T = any> {
305
- readonly node: TreeNode<T>;
306
- readonly path: readonly TreeNode<T>[];
307
- readonly depth: number;
308
- readonly index: number;
309
- }
310
- type TreePredicate<T = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => boolean;
311
- type TreeTransformer<T = any, R = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => R;
312
- type TreeVisitor<T = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => void | boolean;
313
- declare class Tree {
314
- private static dfsGenerator;
315
- private static bfsGenerator;
316
- private static selectStrategy;
317
- /**
318
- * 从扁平数组创建树形结构
319
- *
320
- * @category Data Structures
321
- * @param list 扁平数组数据
322
- * @param config 树形配置选项
323
- * @returns 树形结构数组
324
- * @example
325
- * ```ts
326
- * const flatData = [
327
- * { id: '1', name: '部门1', parentId: null },
328
- * { id: '2', name: '部门1-1', parentId: '1' },
329
- * { id: '3', name: '部门1-2', parentId: '1' },
330
- * { id: '4', name: '部门1-1-1', parentId: '2' }
331
- * ]
332
- *
333
- * const tree = Tree.fromList(flatData, {
334
- * id: 'id',
335
- * pid: 'parentId',
336
- * children: 'children'
337
- * })
338
- *
339
- * console.log(tree) // 转换为树形结构
340
- * ```
341
- */
342
- static fromList<T = any>(list: T[], config?: TreeConfigInput): TreeNode<T>[];
343
- /**
344
- * 将树形结构转换为扁平数组
345
- *
346
- * @category Data Structures
347
- * @param tree 树形结构(单个节点或节点数组)
348
- * @param config 树形配置选项
349
- * @returns 扁平数组
350
- * @example
351
- * ```ts
352
- * const tree = [
353
- * {
354
- * id: '1',
355
- * name: '根节点',
356
- * children: [
357
- * { id: '2', name: '子节点1', children: [] },
358
- * { id: '3', name: '子节点2', children: [] }
359
- * ]
360
- * }
361
- * ]
362
- *
363
- * const flatList = Tree.toList(tree)
364
- * console.log(flatList) // [{ id: '1', name: '根节点' }, { id: '2', name: '子节点1' }, ...]
365
- * ```
366
- */
367
- static toList<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): T[];
368
- /**
369
- * 估算树形结构的节点数量
370
- *
371
- * @category Data Structures
372
- * @param tree 树形结构(单个节点或节点数组)
373
- * @param config 树形配置选项
374
- * @returns 节点总数量
375
- * @example
376
- * ```ts
377
- * const tree = [
378
- * {
379
- * id: '1',
380
- * name: '根节点',
381
- * children: [
382
- * { id: '2', name: '子节点1', children: [] },
383
- * { id: '3', name: '子节点2', children: [] }
384
- * ]
385
- * }
386
- * ]
387
- *
388
- * const size = Tree.estimateSize(tree)
389
- * console.log(size) // 3
390
- * ```
391
- */
392
- static estimateSize<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): number;
393
- /**
394
- * 查找树中第一个满足条件的节点
395
- *
396
- * @category Data Structures
397
- * @param tree 树形结构(单个节点或节点数组)
398
- * @param predicate 查找条件函数
399
- * @param config 树形配置选项
400
- * @returns 匹配的节点结果,包含节点、路径、深度和索引信息;未找到时返回undefined
401
- * @example
402
- * ```ts
403
- * const tree = [
404
- * {
405
- * id: '1',
406
- * name: '部门1',
407
- * children: [
408
- * { id: '2', name: '部门1-1', children: [] }
409
- * ]
410
- * }
411
- * ]
412
- *
413
- * const result = Tree.find(tree, (node) => node.name === '部门1-1')
414
- * console.log(result?.node.id) // '2'
415
- * console.log(result?.depth) // 1
416
- * ```
417
- */
418
- static find<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
419
- /**
420
- * 查找树中所有满足条件的节点
421
- *
422
- * @category Data Structures
423
- * @param tree 树形结构(单个节点或节点数组)
424
- * @param predicate 查找条件函数
425
- * @param config 树形配置选项
426
- * @returns 所有匹配的节点结果数组,每个结果包含节点、路径、深度和索引信息
427
- * @example
428
- * ```ts
429
- * const tree = [
430
- * {
431
- * id: '1',
432
- * type: 'folder',
433
- * name: '根目录',
434
- * children: [
435
- * { id: '2', type: 'file', name: '文件1', children: [] },
436
- * { id: '3', type: 'file', name: '文件2', children: [] }
437
- * ]
438
- * }
439
- * ]
440
- *
441
- * const files = Tree.findAll(tree, (node) => node.type === 'file')
442
- * console.log(files.length) // 2
443
- * ```
444
- */
445
- static findAll<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T>[];
446
- /**
447
- * 根据ID查找树中的节点
448
- *
449
- * @category Data Structures
450
- * @param tree 树形结构(单个节点或节点数组)
451
- * @param id 要查找的节点ID
452
- * @param config 树形配置选项
453
- * @returns 匹配的节点结果,包含节点、路径、深度和索引信息;未找到时返回undefined
454
- * @example
455
- * ```ts
456
- * const tree = [
457
- * {
458
- * id: '1',
459
- * name: '根节点',
460
- * children: [
461
- * { id: '2', name: '子节点', children: [] }
462
- * ]
463
- * }
464
- * ]
465
- *
466
- * const result = Tree.findById(tree, '2')
467
- * console.log(result?.node.name) // '子节点'
468
- * ```
469
- */
470
- static findById<T = any>(tree: TreeNode<T> | TreeNode<T>[], id: string, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
471
- /**
472
- * 获取树形结构的统计信息
473
- *
474
- * @category Data Structures
475
- * @param tree 树形结构(单个节点或节点数组)
476
- * @param config 树形配置选项
477
- * @returns 树的统计信息,包含总节点数、叶子节点数、最大深度和分支节点数
478
- * @example
479
- * ```ts
480
- * const tree = [
481
- * {
482
- * id: '1',
483
- * name: '根节点',
484
- * children: [
485
- * { id: '2', name: '子节点1', children: [] },
486
- * { id: '3', name: '子节点2', children: [
487
- * { id: '4', name: '孙节点', children: [] }
488
- * ] }
489
- * ]
490
- * }
491
- * ]
492
- *
493
- * const stats = Tree.getStats(tree)
494
- * console.log(stats) // { total: 4, leaves: 2, depth: 3, branches: 2 }
495
- * ```
496
- */
497
- static getStats<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): TreeStats;
498
- /**
499
- * 过滤树形结构,保留满足条件的节点及其祖先和后代
500
- *
501
- * @category Data Structures
502
- * @param tree 树形结构(单个节点或节点数组)
503
- * @param predicate 过滤条件函数
504
- * @param config 树形配置选项
505
- * @returns 过滤后的树形结构数组
506
- * @example
507
- * ```ts
508
- * const tree = [
509
- * {
510
- * id: '1',
511
- * type: 'folder',
512
- * name: '根目录',
513
- * children: [
514
- * { id: '2', type: 'file', name: '文档.txt', children: [] },
515
- * { id: '3', type: 'folder', name: '子目录', children: [
516
- * { id: '4', type: 'file', name: '图片.jpg', children: [] }
517
- * ] }
518
- * ]
519
- * }
520
- * ]
521
- *
522
- * const filtered = Tree.filter(tree, (node) => node.type === 'file')
523
- * // 返回包含所有文件节点及其父级路径的树结构
524
- * ```
525
- */
526
- static filter<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNode<T>[];
527
- /**
528
- * 转换树形结构,将每个节点转换为新的结构
529
- *
530
- * @category Data Structures
531
- * @param tree 树形结构(单个节点或节点数组)
532
- * @param transformer 节点转换函数
533
- * @param config 树形配置选项
534
- * @returns 转换后的树形结构数组
535
- * @example
536
- * ```ts
537
- * const tree = [
538
- * {
539
- * id: '1',
540
- * name: '部门1',
541
- * children: [
542
- * { id: '2', name: '部门1-1', children: [] }
543
- * ]
544
- * }
545
- * ]
546
- *
547
- * const transformed = Tree.transform(tree, (node, depth) => ({
548
- * key: node.id,
549
- * title: node.name,
550
- * level: depth
551
- * }))
552
- * // 转换为新的数据结构
553
- * ```
554
- */
555
- static transform<T = any, R = any>(tree: TreeNode<T> | TreeNode<T>[], transformer: TreeTransformer<T, R>, config?: TreeConfigInput): TreeNode<R>[];
556
- /**
557
- * 遍历树形结构的每个节点
558
- *
559
- * @category Data Structures
560
- * @param tree 树形结构(单个节点或节点数组)
561
- * @param visitor 访问者函数,返回false可以跳过子节点的遍历
562
- * @param config 树形配置选项
563
- * @example
564
- * ```ts
565
- * const tree = [
566
- * {
567
- * id: '1',
568
- * name: '根节点',
569
- * children: [
570
- * { id: '2', name: '子节点', children: [] }
571
- * ]
572
- * }
573
- * ]
574
- *
575
- * Tree.forEach(tree, (node, depth) => {
576
- * console.log(`${' '.repeat(depth * 2)}${node.name}`)
577
- * // 输出缩进的树结构
578
- * })
579
- * ```
580
- */
581
- static forEach<T = any>(tree: TreeNode<T> | TreeNode<T>[], visitor: TreeVisitor<T>, config?: TreeConfigInput): void;
582
- /**
583
- * 在指定节点前插入新节点
584
- *
585
- * @category Data Structures
586
- * @param tree 树形结构数组
587
- * @param targetId 目标节点的ID
588
- * @param newNode 要插入的新节点数据
589
- * @param config 树形配置选项
590
- * @returns 是否成功插入
591
- * @example
592
- * ```ts
593
- * const tree = [
594
- * {
595
- * id: '1',
596
- * name: '节点1',
597
- * children: [
598
- * { id: '2', name: '节点2', children: [] }
599
- * ]
600
- * }
601
- * ]
602
- *
603
- * const success = Tree.insertBefore(tree, '2', { id: '1.5', name: '新节点' })
604
- * console.log(success) // true
605
- * ```
606
- */
607
- static insertBefore<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
608
- /**
609
- * 在指定节点后插入新节点
610
- *
611
- * @category Data Structures
612
- * @param tree 树形结构数组
613
- * @param targetId 目标节点的ID
614
- * @param newNode 要插入的新节点数据
615
- * @param config 树形配置选项
616
- * @returns 是否成功插入
617
- * @example
618
- * ```ts
619
- * const tree = [
620
- * {
621
- * id: '1',
622
- * name: '节点1',
623
- * children: [
624
- * { id: '2', name: '节点2', children: [] }
625
- * ]
626
- * }
627
- * ]
628
- *
629
- * const success = Tree.insertAfter(tree, '2', { id: '3', name: '新节点' })
630
- * console.log(success) // true
631
- * ```
632
- */
633
- static insertAfter<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
634
- /**
635
- * 从树中删除指定节点
636
- *
637
- * @category Data Structures
638
- * @param tree 树形结构数组
639
- * @param targetId 要删除的节点ID
640
- * @param config 树形配置选项
641
- * @returns 被删除的节点,未找到时返回undefined
642
- * @example
643
- * ```ts
644
- * const tree = [
645
- * {
646
- * id: '1',
647
- * name: '根节点',
648
- * children: [
649
- * { id: '2', name: '子节点', children: [] }
650
- * ]
651
- * }
652
- * ]
653
- *
654
- * const removed = Tree.remove(tree, '2')
655
- * console.log(removed?.name) // '子节点'
656
- * ```
657
- */
658
- static remove<T = any>(tree: TreeNode<T>[], targetId: string, config?: TreeConfigInput): TreeNode<T> | undefined;
659
- /**
660
- * 验证树形结构的有效性
661
- *
662
- * @category Data Structures
663
- * @param tree 树形结构(单个节点或节点数组)
664
- * @param config 树形配置选项
665
- * @returns 验证结果,包含是否有效和错误信息数组
666
- * @example
667
- * ```ts
668
- * const tree = [
669
- * {
670
- * id: '1',
671
- * name: '根节点',
672
- * children: [
673
- * { id: '2', name: '子节点', children: [] }
674
- * ]
675
- * }
676
- * ]
677
- *
678
- * const result = Tree.validate(tree)
679
- * console.log(result.isValid) // true
680
- * console.log(result.errors) // []
681
- * ```
682
- */
683
- static validate<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): {
684
- isValid: boolean;
685
- errors: string[];
686
- };
687
- }
688
-
689
- /**
690
- * 数组去重,返回去除重复元素后的新数组
691
- *
692
- * @category Array
693
- * @param arr 待去重的数组
694
- * @returns 去重后的新数组
695
- * @example
696
- * ```ts
697
- * const numbers = [1, 2, 2, 3, 3, 4]
698
- * const uniqueNumbers = unique(numbers)
699
- * console.log(uniqueNumbers) // [1, 2, 3, 4]
700
- *
701
- * const strings = ['a', 'b', 'a', 'c']
702
- * const uniqueStrings = unique(strings)
703
- * console.log(uniqueStrings) // ['a', 'b', 'c']
704
- * ```
705
- */
706
- declare function unique<T>(arr: T[]): T[];
707
- /**
708
- * 将数组分割成指定大小的块
709
- *
710
- * @category Array
711
- * @param arr 待分割的数组
712
- * @param size 每个块的大小
713
- * @returns 分割后的二维数组
714
- * @example
715
- * ```ts
716
- * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
717
- * const chunks = chunk(numbers, 3)
718
- * console.log(chunks) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
719
- *
720
- * const names = ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
721
- * const pairs = chunk(names, 2)
722
- * console.log(pairs) // [['Alice', 'Bob'], ['Charlie', 'David'], ['Eve']]
723
- * ```
724
- */
725
- declare function chunk<T>(arr: T[], size: number): T[][];
726
- /**
727
- * 数组扁平化,将嵌套数组展平到指定深度
728
- *
729
- * @category Array
730
- * @param arr 待扁平化的数组
731
- * @param depth 扁平化深度,默认为1
732
- * @returns 扁平化后的数组
733
- * @example
734
- * ```ts
735
- * const nested = [1, [2, 3], [4, [5, 6]]]
736
- * const flat1 = flatten(nested)
737
- * console.log(flat1) // [1, 2, 3, 4, [5, 6]]
738
- *
739
- * const flat2 = flatten(nested, 2)
740
- * console.log(flat2) // [1, 2, 3, 4, 5, 6]
741
- * ```
742
- */
743
- declare function flatten<T>(arr: T[], depth?: number): any[];
744
-
745
- /**
746
- * 防抖函数,在指定时间内多次触发只执行最后一次
747
- *
748
- * @category Async
749
- * @param func 需要防抖的函数
750
- * @param wait 防抖延迟时间(毫秒)
751
- * @returns 防抖处理后的函数
752
- * @example
753
- * ```ts
754
- * const debouncedSearch = debounce((query: string) => {
755
- * console.log('搜索:', query)
756
- * }, 300)
757
- *
758
- * // 连续调用,只有最后一次会执行
759
- * debouncedSearch('a')
760
- * debouncedSearch('ab')
761
- * debouncedSearch('abc') // 只有这次会在300ms后执行
762
- * ```
763
- */
764
- declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
765
-
766
- /**
767
- * 延迟执行函数,返回一个在指定时间后resolve的Promise
768
- *
769
- * @category Async
770
- * @param ms 延迟时间(毫秒)
771
- * @returns 延迟Promise
772
- * @example
773
- * ```ts
774
- * // 延迟1秒后继续执行
775
- * await sleep(1000)
776
- * console.log('1秒后执行')
777
- *
778
- * // 在异步函数中使用
779
- * async function delayedOperation() {
780
- * console.log('开始')
781
- * await sleep(500)
782
- * console.log('500ms后执行')
783
- * }
784
- * ```
785
- */
786
- declare function sleep(ms: number): Promise<void>;
787
- /**
788
- * 可取消的延迟函数,返回Promise和取消函数
789
- *
790
- * @category Async
791
- * @param ms 延迟时间(毫秒)
792
- * @returns 包含Promise和取消函数的对象
793
- * @example
794
- * ```ts
795
- * const { promise, cancel } = sleepWithCancel(5000)
796
- *
797
- * // 在另一个地方取消延迟
798
- * setTimeout(() => {
799
- * cancel() // 取消延迟
800
- * }, 2000)
801
- *
802
- * try {
803
- * await promise
804
- * console.log('5秒后执行')
805
- * } catch (error) {
806
- * console.log('延迟被取消')
807
- * }
808
- * ```
809
- */
810
- declare function sleepWithCancel(ms: number): {
811
- promise: Promise<void>;
812
- 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;
813
593
  };
814
594
 
815
595
  /**
@@ -994,34 +774,34 @@ declare function replaceCurrentColor(path: string, color?: string): Promise<stri
994
774
  declare function convertToKebabCase<T extends AnyObject>(obj: T, deep?: boolean): T;
995
775
 
996
776
  /**
997
- * 深度克隆对象,创建完全独立的副本
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`。
998
784
  *
999
785
  * @category Object
1000
- * @param obj 待克隆的对象
1001
- * @returns 深度克隆后的对象
786
+ * @typeParam T 拷贝值的类型
787
+ * @param obj 要被深拷贝的值
788
+ * @param cache 内部使用的 `WeakMap`(循环引用记忆化),一般不需要传入
789
+ * @returns 新的深拷贝值,与输入值结构等价、引用独立
790
+ *
1002
791
  * @example
1003
792
  * ```ts
1004
- * const original = {
1005
- * name: 'John',
1006
- * age: 30,
1007
- * address: {
1008
- * city: 'New York',
1009
- * zip: '10001'
1010
- * },
1011
- * hobbies: ['reading', 'coding']
1012
- * }
1013
- *
1014
- * const cloned = deepClone(original)
1015
- * cloned.address.city = 'Los Angeles'
1016
- * cloned.hobbies.push('gaming')
1017
- *
1018
- * console.log(original.address.city) // 'New York' (未改变)
1019
- * console.log(original.hobbies.length) // 2 (未改变)
1020
- * console.log(cloned.address.city) // 'Los Angeles'
1021
- * 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
1022
799
  * ```
800
+ *
801
+ * @remarks
802
+ * 若对象包含不可克隆资源(如带有原生句柄的自定义对象),请在外层进行自定义序列化逻辑或为该类型添加专用分支。
1023
803
  */
1024
- declare function deepClone<T>(obj: T): T;
804
+ declare function deepClone<T>(obj: T, cache?: WeakMap<object, any>): T;
1025
805
 
1026
806
  /**
1027
807
  * 从对象中排除指定的键,返回新对象
@@ -1039,42 +819,157 @@ declare function deepClone<T>(obj: T): T;
1039
819
  * email: 'john@example.com'
1040
820
  * }
1041
821
  *
1042
- * const publicUser = omit(user, ['password'])
1043
- * console.log(publicUser) // { id: 1, name: 'John', email: 'john@example.com' }
822
+ * const publicUser = omit(user, ['password'])
823
+ * console.log(publicUser) // { id: 1, name: 'John', email: 'john@example.com' }
824
+ *
825
+ * const basicInfo = omit(user, ['password', 'email'])
826
+ * console.log(basicInfo) // { id: 1, name: 'John' }
827
+ * ```
828
+ */
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 本身
1044
908
  *
1045
- * const basicInfo = omit(user, ['password', 'email'])
1046
- * console.log(basicInfo) // { id: 1, name: 'John' }
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 本身
1047
922
  * ```
1048
923
  */
1049
- declare function omit<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): OmitByKey<T, K>;
924
+ declare function getPath<T, D = undefined>(object: T, path: PathInput, defaultValue?: D): unknown | D;
1050
925
  /**
1051
- * 从对象中排除值为undefined的键
926
+ * 在对象指定路径写入值。缺失路径会被自动创建:
927
+ * - 下一段为 number(索引)时创建数组
928
+ * - 下一段为 string(属性)时创建对象
929
+ *
930
+ * 若中途遇到非容器类型(如字符串/数值/布尔),会被替换为正确的容器以继续写入。
1052
931
  *
1053
932
  * @category Object
1054
- * @param obj 源对象
1055
- * @returns 排除undefined值后的新对象
933
+ * @param object 目标对象(原地修改并返回同一引用)
934
+ * @param path 路径字符串或片段数组
935
+ * @param value 要写入的值
936
+ * @returns 原对象(已修改)
1056
937
  * @example
1057
938
  * ```ts
1058
- * const data = {
1059
- * name: 'John',
1060
- * age: undefined,
1061
- * city: 'New York',
1062
- * country: undefined
1063
- * }
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
+ * 将片段数组序列化为路径字符串。
1064
956
  *
1065
- * const cleaned = omitUndefined(data)
1066
- * console.log(cleaned) // { name: 'John', city: 'New York' }
957
+ * 规则:
958
+ * - 合法标识符段使用点拼接(a.b.c)
959
+ * - 数字段转为索引([0])
960
+ * - 其它需要转义的键使用方括号引号(['x.y']),并转义 \\ 与 '\''
1067
961
  *
1068
- * // 用于API请求前清理数据
1069
- * const requestData = omitUndefined({
1070
- * title: 'Post Title',
1071
- * content: 'Post content',
1072
- * tags: undefined,
1073
- * published: true
1074
- * })
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']
1075
970
  * ```
1076
971
  */
1077
- declare function omitUndefined<T extends AnyObject>(obj: T): Partial<T>;
972
+ declare function joinPath(segments: (string | number)[]): string;
1078
973
 
1079
974
  /**
1080
975
  * 从对象中选择指定的键,返回新对象
@@ -1159,50 +1054,677 @@ declare function separateMany<T extends AnyObject, M extends Record<string, read
1159
1054
  };
1160
1055
 
1161
1056
  /**
1162
- * 将字符串首字母大写
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
+ * 将字符串首字母大写,其余字母小写。
1163
1133
  *
1164
1134
  * @category String
1165
- * @param str 待处理的字符串
1135
+ * @param str 要转换的字符串
1166
1136
  * @returns 首字母大写的字符串
1167
1137
  * @example
1168
1138
  * ```ts
1169
- * console.log(capitalize('hello')) // 'Hello'
1170
- * console.log(capitalize('WORLD')) // 'WORLD'
1171
- * console.log(capitalize('')) // ''
1172
- * console.log(capitalize('a')) // 'A'
1139
+ * capitalize('hello') // 'Hello'
1140
+ * capitalize('HELLO') // 'Hello'
1141
+ * capitalize('hello world') // 'Hello world'
1173
1142
  * ```
1174
1143
  */
1175
1144
  declare function capitalize(str: string): string;
1176
1145
  /**
1177
- * 将驼峰命名转换为kebab-case
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;
1173
+ /**
1174
+ * 将字符串转换为大写格式,单词之间用空格分隔。
1175
+ *
1176
+ * @category String
1177
+ * @param str 要转换的字符串
1178
+ * @returns 大写格式的字符串
1179
+ * @example
1180
+ * ```ts
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
+ * 将字符串转换为小写格式,单词之间用空格分隔。
1178
1190
  *
1179
1191
  * @category String
1180
- * @param str 驼峰命名的字符串
1181
- * @returns kebab-case格式的字符串
1192
+ * @param str 要转换的字符串
1193
+ * @returns 小写格式的字符串
1182
1194
  * @example
1183
1195
  * ```ts
1184
- * console.log(camelToKebab('helloWorld')) // 'hello-world'
1185
- * console.log(camelToKebab('firstName')) // 'first-name'
1186
- * console.log(camelToKebab('XMLHttpRequest')) // 'x-m-l-http-request'
1187
- * console.log(camelToKebab('hello')) // 'hello'
1196
+ * lowerCase('firstName') // 'first name'
1197
+ * lowerCase('First_Name') // 'first name'
1198
+ * lowerCase('FIRST-NAME') // 'first name'
1199
+ * lowerCase('XMLHttpRequest') // 'xml http request'
1188
1200
  * ```
1189
1201
  */
1190
- declare function camelToKebab(str: string): string;
1202
+ declare function lowerCase(str: string): string;
1203
+ /**
1204
+ * 将驼峰命名转换为kebab-case
1205
+ * @deprecated Use `kebabCase` instead
1206
+ */
1207
+ declare const camelToKebab: typeof kebabCase;
1191
1208
  /**
1192
1209
  * 将kebab-case转换为驼峰命名
1210
+ * @deprecated Use `camelCase` instead
1211
+ */
1212
+ declare const kebabToCamel: typeof camelCase;
1213
+
1214
+ /**
1215
+ * 将字符串分解为单词数组。支持camelCase、snake_case、kebab-case等各种命名风格。
1193
1216
  *
1194
1217
  * @category String
1195
- * @param str kebab-case格式的字符串
1196
- * @returns 驼峰命名的字符串
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']
1226
+ * ```
1227
+ */
1228
+ declare function words(str: string): string[];
1229
+
1230
+ /**
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`
1324
+ *
1197
1325
  * @example
1198
1326
  * ```ts
1199
- * console.log(kebabToCamel('hello-world')) // 'helloWorld'
1200
- * console.log(kebabToCamel('first-name')) // 'firstName'
1201
- * console.log(kebabToCamel('background-color')) // 'backgroundColor'
1202
- * console.log(kebabToCamel('hello')) // 'hello'
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
+ * ]
1337
+ *
1338
+ * // 查找节点
1339
+ * const node = Tree.find(tree, ({ node }) => node.name === '子节点1')
1340
+ *
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
+ * }))
1203
1352
  * ```
1204
1353
  */
1205
- declare function kebabToCamel(str: string): string;
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
+ };
1727
+ }
1206
1728
 
1207
1729
  /**
1208
1730
  * 生成字符串的简单哈希值
@@ -1338,6 +1860,21 @@ declare function isFunction(value: any): value is (...args: any[]) => any;
1338
1860
  * ```
1339
1861
  */
1340
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>;
1341
1878
 
1342
- 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, separateMany, simpleHash, sleep, sleepWithCancel, throttle, triggerDownload, unique, useAppStorage, useCopyCode };
1343
- export type { AnyObject, ApiAwaitable, ApiAwaitedReturn, ApiUnwrapPromise, AppStorageReturn, DeepPartial, FirstParam, FirstParameter, GetObjectField, MutableByKeys, OmitByKey, PartialByKeys, PickByKey, ReadonlyByKeys, RenameKeys, RequiredByKeys, StorageConfig, StorageConfigInput, StorageType, StringOrVNode, UnionToIntersection, UnknownObject };
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 };