@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/README.md +98 -147
- package/dist/index.d.mts +1370 -666
- package/dist/index.d.ts +1370 -666
- package/dist/index.mjs +1 -1
- package/package.json +34 -38
package/dist/index.d.ts
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
* @
|
|
858
|
-
* @
|
|
786
|
+
* @typeParam T 拷贝值的类型
|
|
787
|
+
* @param obj 要被深拷贝的值
|
|
788
|
+
* @param cache 内部使用的 `WeakMap`(循环引用记忆化),一般不需要传入
|
|
789
|
+
* @returns 新的深拷贝值,与输入值结构等价、引用独立
|
|
790
|
+
*
|
|
859
791
|
* @example
|
|
860
792
|
* ```ts
|
|
861
|
-
* const
|
|
862
|
-
*
|
|
863
|
-
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
*
|
|
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
|
-
*
|
|
1174
|
+
* 将字符串转换为大写格式,单词之间用空格分隔。
|
|
909
1175
|
*
|
|
910
|
-
* @category
|
|
911
|
-
* @param
|
|
912
|
-
* @returns
|
|
1176
|
+
* @category String
|
|
1177
|
+
* @param str 要转换的字符串
|
|
1178
|
+
* @returns 大写格式的字符串
|
|
913
1179
|
* @example
|
|
914
1180
|
* ```ts
|
|
915
|
-
*
|
|
916
|
-
*
|
|
917
|
-
*
|
|
918
|
-
*
|
|
919
|
-
*
|
|
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
|
-
*
|
|
923
|
-
*
|
|
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
|
-
*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
*
|
|
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
|
|
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
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
*
|
|
951
|
-
*
|
|
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
|
-
*
|
|
955
|
-
*
|
|
1338
|
+
* // 查找节点
|
|
1339
|
+
* const node = Tree.find(tree, ({ node }) => node.name === '子节点1')
|
|
956
1340
|
*
|
|
957
|
-
*
|
|
958
|
-
*
|
|
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
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
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 };
|