import { Ref, MaybeRefOrGetter, ComputedRef, DeepReadonly, VNode, Component, DefineComponent } from 'vue'; import { UseInfiniteScrollReturn, MaybeComputedElementRef } from '@vueuse/core'; type StorageType = 'localStorage' | 'sessionStorage'; interface StorageConfig { key: string; defaultValue: T; prefix: string; storage: StorageType; } type StorageConfigInput = Partial, 'key' | 'defaultValue'>> & { key: string; defaultValue: T; }; interface AppStorageReturn { state: Ref; getItem: () => T; setItem: (value: T) => void; removeItem: () => void; } /** * 应用存储管理的组合式函数,支持 localStorage 和 sessionStorage * * @category Composables * @param config 存储配置对象 * @returns 存储管理对象,包含响应式状态和操作方法 * @example * ```ts * // 创建存储管理实例 * const { state, setItem, getItem, removeItem } = useAppStorage({ * key: 'user-preferences', * defaultValue: { * theme: 'light', * language: 'zh-CN', * fontSize: 16 * }, * storage: 'localStorage', * prefix: 'app' * }) * * // 使用响应式状态 * console.log(state.value.theme) // 'light' * * // 更新设置 * setItem({ * theme: 'dark', * language: 'en-US', * fontSize: 18 * }) * ``` */ declare function useAppStorage(config: StorageConfigInput): AppStorageReturn; /** * 复制文本到剪贴板的组合式函数 * * @category Composables * @param text 要复制的文本内容 * @returns 复制是否成功的Promise * @example * ```ts * // 复制简单文本 * const copyText = async () => { * const success = await useCopyCode('Hello, World!') * if (success) { * console.log('复制成功') * } else { * console.log('复制失败') * } * } * * // 复制代码块 * const copyCodeBlock = async () => { * const code = ` * function hello() { * console.log('Hello, World!') * } * ` * const success = await useCopyCode(code) * if (success) { * // 显示复制成功提示 * showNotification('代码已复制到剪贴板') * } * } * * // 在点击事件中使用 * const handleCopy = () => { * useCopyCode(document.getElementById('code').textContent) * } * ``` */ declare function useCopyCode(text: string): Promise; interface UseInfiniteScrollBindingOptions { /** * 触发加载的距离阈值(px) * * 注意:vueuse 的 useInfiniteScroll 仅在初始化时读取 distance, * 后续变化不会生效,因此即便接受 ref/getter 也只在 setup 阶段求值一次 */ distance: MaybeRefOrGetter; /** * 是否允许继续加载 * @default () => true */ canLoadMore?: MaybeRefOrGetter; /** 触发加载的回调 */ onLoadMore: () => void | Promise; /** * 触发方向 * @default 'bottom' */ direction?: 'top' | 'bottom' | 'left' | 'right'; /** * 两次触发之间的最小间隔(ms) * @default 100 */ interval?: number; } /** * 基于 vueuse `useInfiniteScroll` 的薄包装 * * 主要价值:把 `canLoadMore` 暴露为 `MaybeRefOrGetter`, * 避免调用方重复写 `() => ...` 闭包;并原样透传 `direction` / `interval` * 与 `useInfiniteScroll` 的返回值(`isLoading` / `reset`)。 * * @category Composables * @example * ```ts * const { isLoading, reset } = useInfiniteScrollBinding( * () => listRef.value, * { * distance: 100, * canLoadMore: () => hasMore.value, * onLoadMore: () => fetchNextPage() * } * ) * ``` */ declare function useInfiniteScrollBinding(getEl: () => HTMLElement | null | undefined, options: UseInfiniteScrollBindingOptions): UseInfiniteScrollReturn; interface UseOverflowDetectionOptions { /** * 是否监听内容变化(MutationObserver) * * 静态内容场景可关闭以节省开销 * @default true */ observeContent?: boolean; } interface UseOverflowDetectionReturn { /** 任一方向溢出 = overflowX || overflowY */ overflowed: ComputedRef; /** 水平方向是否被截断 */ overflowX: DeepReadonly>; /** 垂直方向是否被截断 */ overflowY: DeepReadonly>; /** 手动触发一次重新检测 */ check: () => void; } /** * 检测元素文本内容是否被截断 * * 自动追踪尺寸变化(ResizeObserver)与可选的内容变化(MutationObserver), * 并根据 computed style 推断单行 / line-clamp / 通用三种测量策略。调用方 * 只需在元素上正确应用 truncate / line-clamp CSS,无需额外配置。 * * @category Composables * @param target 目标元素引用(支持 ref / 模板 ref / getter) * @param options 可选配置 * @example * ```ts * const el = useTemplateRef('el') * const { overflowed, overflowX, overflowY } = useOverflowDetection(el) * ``` */ declare function useOverflowDetection(target: MaybeComputedElementRef, options?: UseOverflowDetectionOptions): UseOverflowDetectionReturn; interface RegistryOptions { /** * 是否使用 `shallowReactive` 存储,使 `computed` / `watch` 能感知注册与注销 * @defaultValue false */ reactive?: boolean; /** * 同一 id 重复注册时触发,用于告警。不改变「后者接管」的行为 */ onDuplicate?: (id: string) => void; } interface Registry { /** * 注册实例,返回注销句柄。 * * 句柄仅在当前值仍是本次注册的值时才删除,因此新旧实例交替期间旧句柄不会误删新注册。 */ register: (id: string, value: T) => () => void; /** 按 id 注销,返回是否确实删除了条目 */ unregister: (id: string) => boolean; get: (id: string) => T | undefined; has: (id: string) => boolean; /** 已注册的 id 列表,按注册先后排列 */ keys: () => string[]; clear: () => void; readonly size: number; } /** * 创建按 id 索引实例的注册表 * * 适用于跨组件树、跨路由访问实例的场景:组件挂载时注册,卸载时调用 `register` * 返回的句柄注销。开启 `reactive` 后可直接在 `computed` 中读取。 * * @category Helpers * @typeParam T 注册值的类型 * @param options 注册表行为配置 * @returns 注册表实例 * @example * ```ts * const registry = createRegistry() * * const dispose = registry.register('main', map) * registry.get('main') // MapInstance * dispose() * ``` * @example * ```ts * // 响应式模式:跨树门面用 computed 读取,注册与注销都会触发重算 * const registry = createRegistry({ * reactive: true, * onDuplicate: id => console.warn(`"${id}" 已注册,后者接管`), * }) * const draw = computed(() => registry.get(mapId)) * ``` */ declare function createRegistry(options?: RegistryOptions): Registry; /** * 将SVG字符串转换为PNG格式的Blob对象 * * @category File * @param svg SVG字符串 * @returns PNG格式的Blob对象 * @throws 当SVG无效或转换失败时抛出错误 * @example * ```ts * const svgString = '' * * try { * const pngBlob = await convertSvgToPng(svgString) * const url = URL.createObjectURL(pngBlob) * * // 用于下载或显示 * const img = document.createElement('img') * img.src = url * document.body.appendChild(img) * } catch (error) { * console.error('SVG转换失败:', error) * } * ``` */ declare function convertSvgToPng(svg: string): Promise; /** * 从响应头中提取文件名 * * @category File * @param headers 响应头对象 * @param fallbackName 默认文件名 * @returns 提取的文件名 * @example * ```ts * // 从响应头中提取文件名 * const headers = new Headers({ * 'content-disposition': 'attachment; filename="report.pdf"' * }) * const filename = extractFilename(headers, 'download') * console.log(filename) // 'report.pdf' * * // 处理编码的文件名 * const encodedHeaders = new Headers({ * 'content-disposition': 'attachment; filename*=UTF-8\'\'%E6%8A%A5%E5%91%8A.pdf' * }) * const encodedFilename = extractFilename(encodedHeaders) * console.log(encodedFilename) // '报告.pdf' * ``` */ declare function extractFilename(headers?: Headers, fallbackName?: string): string; /** * 格式化文件大小,将字节数转换为可读的文件大小字符串 * * @category File * @param bytes 文件大小(字节) * @returns 格式化后的文件大小字符串 * @example * ```ts * console.log(formatFileSize(1024)) // '1 KB' * console.log(formatFileSize(1536)) // '1.5 KB' * console.log(formatFileSize(1048576)) // '1 MB' * console.log(formatFileSize(1073741824)) // '1 GB' * * // 处理边界情况 * console.log(formatFileSize(0)) // '0 Bytes' * console.log(formatFileSize(-100)) // '0 Bytes' * ``` */ declare function formatFileSize(bytes: number): string; /** * 替换SVG文件中的currentColor为指定颜色 * * @category File * @param path SVG文件路径 * @param color 替换的颜色值,不提供则返回原始SVG * @returns 处理后的SVG字符串 * @throws 当文件获取失败或SVG无效时抛出错误 * @example * ```ts * // 获取并替换SVG中的currentColor * try { * const svgContent = await replaceCurrentColor('/icons/star.svg', '#ff0000') * const container = document.createElement('div') * container.innerHTML = svgContent * document.body.appendChild(container) * } catch (error) { * console.error('SVG处理失败:', error) * } * * // 只获取SVG内容,不替换颜色 * const originalSvg = await replaceCurrentColor('/icons/star.svg') * ``` */ declare function replaceCurrentColor(path: string, color?: string): Promise; /** * 触发浏览器下载文件 * * @category File * @param blob 文件数据 * @param filename 文件名 * @example * ```ts * // 下载文本文件 * const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' }) * triggerDownload(textBlob, 'hello.txt') * * // 下载JSON数据 * const data = { name: 'John', age: 30 } * const jsonBlob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }) * triggerDownload(jsonBlob, 'data.json') * * // 下载图片 * const canvas = document.createElement('canvas') * canvas.toBlob((blob) => { * if (blob) { * triggerDownload(blob, 'image.png') * } * }) * ``` */ declare function triggerDownload(blob: Blob, filename: string): void; /** * 深拷贝任意 JavaScript 值。 * * - 优先使用原生 `structuredClone`(若可用),覆盖 `Map`/`Set`/`TypedArray`/`ArrayBuffer` 等内建类型。 * - 对不支持 `structuredClone` 的环境,使用回退实现: * - 支持循环引用(`WeakMap` 记忆化)。 * - 保留原型与属性描述符(含 getter/setter),复制 symbol 键。 * - 内建类型专项处理:`Date`/`RegExp`/`Map`/`Set`/`ArrayBuffer`/`TypedArray`/`URL`/`Error`。 * * @category Object * @typeParam T 拷贝值的类型 * @param obj 要被深拷贝的值 * @param cache 内部使用的 `WeakMap`(循环引用记忆化),一般不需要传入 * @returns 新的深拷贝值,与输入值结构等价、引用独立 * * @example * ```ts * const source = { a: 1, d: new Date(), m: new Map([[1, { x: 2 }]]) } * const cloned = deepClone(source) * cloned !== source // true * cloned.d !== source.d // true * cloned.m !== source.m // true * cloned.m.get(1) !== source.m.get(1) // true * ``` * * @remarks * 若对象包含不可克隆资源(如带有原生句柄的自定义对象),请在外层进行自定义序列化逻辑或为该类型添加专用分支。 */ declare function deepClone(obj: T, cache?: WeakMap): T; type UnknownObject = Record; type AnyObject = Record; /** * Vue 渲染相关文本/节点类型: 可为字符串、`VNode` 或返回 `VNode` 的函数。 * @example * // 在渲染 API 中允许三种形态: * // - '标题' * // - h('div', '标题') 产生的 VNode * // - () => h('div', '标题') 的惰性渲染函数 */ type StringOrVNode = string | VNode | (() => VNode); /** * 合并两个对象类型,U 中的属性会覆盖 T 中的属性 * * @example * ```ts * type T = { a: number, c: string } * type U = { a: string, b: boolean } * type M = Merge // { a: string, b: boolean, c: string } * ``` */ type Merge = Omit & U; /** * 判断类型 T 是否为纯对象类型 * 纯对象是指普通的对象字面量,排除数组、函数、Date 等特殊对象类型 * @example * ```ts * type Test1 = IsPlainObject<{ a: number }> // true * type Test2 = IsPlainObject // false * type Test3 = IsPlainObject<() => void> // false * type Test4 = IsPlainObject // false * type Test5 = IsPlainObject // false * type Test6 = IsPlainObject // false * ``` */ type IsPlainObject = NonNullable extends Record ? NonNullable extends any[] ? false : NonNullable extends (...args: any[]) => any ? false : NonNullable extends Date ? false : true : false; /** * 递归将对象类型 `T` 的所有属性变为可选(深可选)。 * @typeParam T - 源对象类型 * @example * // type Src = { a: { b: number } } * // type R = DeepPartial * // 结果: R 为 { a?: { b?: number | undefined } | undefined } */ type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] | undefined; }; /** 递归深度计数器,用于限制类型递归层数 */ type MergeDepth = [never, 0, 1, 2, 3, 4]; /** * 递归合并两个对象类型,`U` 中的属性优先级高于 `T`。 * 仅对双方都是纯对象的属性做深度递归,其余类型直接取 `U` 的值。 * * @typeParam T - 基础对象类型 * @typeParam U - 覆盖对象类型 * @typeParam D - 递归深度限制,默认为 4 * * @example * ```ts * type A = { a: { b: number; c: string }; d: boolean } * type B = { a: { b: string; e: number }; f: Date } * type R = DeepMerge * // { a: { b: string; c: string; e: number }; d: boolean; f: Date } * ``` */ type DeepMerge = [D] extends [never] ? T & U : { [K in keyof T | keyof U]: K extends keyof U ? K extends keyof T ? IsPlainObject extends true ? IsPlainObject extends true ? DeepMerge, NonNullable, MergeDepth[D]> : U[K] : U[K] : U[K] : K extends keyof T ? T[K] : never; }; /** * 深度控制类型,用于限制类型递归的深度 * 防止类型计算超出 TypeScript 的递归限制 */ type Depth = [never, 0, 1, 2, 3, 4]; /** * 当 `MaybeObject` 为对象时,返回键 `Key` 对应的属性类型; 否则为 `never`。 * @typeParam MaybeObject - 可能为对象的类型 * @typeParam Key - 目标键名(string) * @example * // type Obj = { id: number } * // type R1 = GetObjectField // 结果: number * // type R2 = GetObjectField // 结果: never */ type GetObjectField = MaybeObject extends Record ? MaybeObject[Key] : never; /** * 提取对象的嵌套键,支持点语法路径 * * @template T 源对象类型 * @template D 递归深度,默认为2 * @example * ```ts * type User = { * name: string * address: { * city: string * country: string * } * } * type Keys = NestedKeys // 'name' | 'address' | 'address.city' | 'address.country' * ``` */ type NestedKeys = [D] extends [never] ? never : { [K in keyof T & string]: IsPlainObject extends true ? K | `${K}.${NestedKeys, Depth[D]>}` : K; }[keyof T & string]; /** * 提取对象中所有纯对象字段的键(包括嵌套的),支持点语法路径 * * @template T 源对象类型 * @template D 递归深度,默认为2 * @example * ```ts * type User = { * name: string * age: number * address: { * city: string * location: { * lat: number * lng: number * } * } * } * type ObjectKeys = ObjectFieldKeys // 'address' | 'address.location' * ``` */ type ObjectFieldKeys = [D] extends [never] ? never : { [K in keyof T & string]: IsPlainObject extends true ? K | `${K}.${ObjectFieldKeys, Depth[D]>}` : never; }[keyof T & string]; /** * 提取对象中所有非对象字段的键 * 排除纯对象字段,只保留原始类型字段的键 * * @template T 源对象类型 * @example * ```ts * type User = { * name: string * age: number * address: { * city: string * } * } * type NonObjectKeys = NonObjectFieldKeys // 'name' | 'age' | 'address.city' * ``` */ type NonObjectFieldKeys = Exclude, ObjectFieldKeys>; /** * 提取对象中所有数组字段的键(包括嵌套的),支持点语法路径 * * @template T 源对象类型 * @template D 递归深度,默认为2 * @example * ```ts * type User = { * name: string * tags: string[] * posts: Array<{ title: string }> * profile: { * hobbies: string[] * } * } * type ArrayKeys = ArrayFieldKeys // 'tags' | 'posts' | 'profile.hobbies' * ``` */ type ArrayFieldKeys = [D] extends [never] ? never : { [K in keyof T & string]: NonNullable extends any[] ? K : IsPlainObject extends true ? `${K}.${ArrayFieldKeys, Depth[D]>}` : never; }[keyof T & string]; /** * 根据路径字符串提取对象属性的类型,支持点语法和嵌套对象 * @example GetFieldValue // string[] * @example GetFieldValue // string */ type GetFieldValue = P extends keyof T ? T[P] : P extends `${infer K}.${infer Rest}` ? K extends keyof T ? T[K] extends undefined ? undefined : GetFieldValue, Rest> : unknown : unknown; /** * 依据键名从对象类型 `T` 中剔除键 `K`。 * @typeParam T - 源对象类型 * @typeParam K - 要剔除的键(必须来自 `keyof T`) * @example * // type User = { id: string; name: string; age: number } * // type R = OmitByKey * // 结果: R 为 { id: string; name: string } */ type OmitByKey = { [P in keyof T as P extends K ? never : P]: T[P]; }; /** * 依据键名从对象类型 `T` 中挑选键 `K`。 * @typeParam T - 源对象类型 * @typeParam K - 要保留的键(必须来自 `keyof T`) * @example * // type User = { id: string; name: string; age: number } * // type R = PickByKey * // 结果: R 为 { id: string; name: string } */ type PickByKey = { [P in keyof T as P extends K ? P : never]: T[P]; }; /** * 基于映射表 `Mapping` 对对象类型 `T` 的键进行重命名。 * 未在映射表中的键保持原名; 映射值为 `PropertyKey`(string/number/symbol)。 * @typeParam T - 源对象类型 * @typeParam Mapping - 旧键到新键名的映射 * @example * // type Src = { a: number; b: string } * // type R = RenameKeys * // 结果: R 为 { id: number; b: string } */ type RenameKeys = { [K in keyof T as K extends keyof Mapping ? Exclude : K]: T[K]; }; /** * 将对象类型 `T` 中的键 `K` 标记为必填(移除可选修饰)。 * @typeParam T - 源对象类型 * @typeParam K - 设为必填的键 * @example * // type User = { id: string; name?: string } * // type R = RequiredByKeys * // 结果: R['name'] 为必填的 string */ type RequiredByKeys = T & { [P in K]-?: T[P]; }; /** * 将对象类型 `T` 中的键 `K` 标记为可选。 * @typeParam T - 源对象类型 * @typeParam K - 设为可选的键 * @example * // type User = { id: string; name: string } * // type R = PartialByKeys * // 结果: R['name'] 为可选(可能为 undefined) */ type PartialByKeys = Omit & Partial>; /** * 将对象类型 `T` 中的键 `K` 标记为只读(浅只读)。 * @typeParam T - 源对象类型 * @typeParam K - 设为只读的键 * @example * // type User = { id: string; name: string } * // type R = ReadonlyByKeys * // 结果: R['id'] 不可被重新赋值 */ type ReadonlyByKeys = T & { readonly [P in K]: T[P]; }; /** * 取消对象类型 `T` 中键 `K` 的只读限制,使其可写(浅层)。 * @typeParam T - 源对象类型 * @typeParam K - 取消只读的键 * @example * // type User = { readonly id: string; name: string } * // type R = MutableByKeys * // 结果: R['id'] 变为可写 */ type MutableByKeys = { -readonly [P in K]: T[P]; } & Omit; /** * 将联合类型 `U` 转换为交叉类型,用于合并联合成员的属性。 * @typeParam U - 联合类型 * @example * // type U = { a: number } | { b: string } * // type R = UnionToIntersection * // 结果: R 为 { a: number } & { b: string } */ type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? { [K in keyof I]: I[K]; } : never; /** * 若对象 `T` 在键 `K` 处的类型为元组,则提取其首个元素类型,否则为 `never`。 * @typeParam T - 具有元组属性的对象类型 * @typeParam K - 属性键 * @example * // type Cfg = { params: [id: string, flag?: boolean] } * // type R = FirstParam * // 结果: R 为 string */ type FirstParam = T[K] extends [infer P, ...any[]] ? P : never; /** * 从函数类型中提取首个参数类型; 若 `T` 非函数类型,则为 `undefined`。 * @typeParam T - 函数类型 * @example * // type Fn = (x: number, y: string) => void * // type R = FirstParameter * // 结果: R 为 number; 若 T 非函数,则为 undefined */ type FirstParameter = T extends (arg: infer P, ...args: any[]) => any ? P : undefined; /** * 强制 TypeScript 展平类型别名,使 IntelliSense 能完整枚举对象的所有属性。 * * 常用于消除交叉类型(`A & B`)的「折叠」显示,让 IDE 悬停时直接展示合并后的属性列表。 * * @typeParam T - 要展平的对象类型 * @example * ```ts * type A = { a: number } & { b: string } * // IDE hover 显示 "{ a: number } & { b: string }" * * type B = Prettify * // IDE hover 显示 "{ a: number; b: string }" * ``` */ type Prettify = { [K in keyof T]: T[K]; } & {}; /** * 从对象类型中提取所有字面量键,过滤掉索引签名(`string`、`number`、`symbol`)。 * * 用于需要精确枚举已知属性而不被索引签名污染 IntelliSense 的场景。 * * @typeParam T - 可能含索引签名的对象类型 * @example * ```ts * interface Config { * debug: boolean * timeout: number * [key: string]: unknown * } * // K = 'debug' | 'timeout'(索引签名 string 被过滤掉) * type K = KnownKeys * ``` */ type KnownKeys = { [K in keyof T]-?: string extends K ? never : number extends K ? never : symbol extends K ? never : K; }[keyof T]; /** * 数组合并策略 * - `'concat'` : 将 source 数组拼接在 target 数组之后(默认) * - `'replace'` : 用 source 数组整体替换 target 数组 * - `'unique'` : 拼接后去重(基于 SameValueZero 比较) */ type ArrayMergeStrategy = 'concat' | 'replace' | 'unique'; /** * null/undefined 处理策略 * - `'skip'` : 忽略 source 中的 null/undefined,保留 target 中的值(默认) * - `'override'` : 允许 source 中的 null/undefined 覆盖 target 中的值 */ type NullHandlingStrategy = 'skip' | 'override'; /** * 自定义合并函数。 * * @param key 当前正在处理的键(string 或 Symbol) * @param targetVal target 中该键的当前值 * @param sourceVal source 中该键的值 * @param path 从根对象到当前层级的键路径 * @returns 返回合并结果;返回 `undefined` 则交由默认逻辑处理 */ type CustomMerger = (key: string | symbol, targetVal: unknown, sourceVal: unknown, path: ReadonlyArray) => unknown; /** * deepMerge 配置选项 */ interface DeepMergeOptions { /** 数组合并策略,默认 `'concat'` */ arrayStrategy?: ArrayMergeStrategy; /** null/undefined 处理策略,默认 `'skip'` */ nullHandling?: NullHandlingStrategy; /** 自定义合并函数,返回 `undefined` 则交由默认逻辑处理 */ customMerger?: CustomMerger; } /** * 递归地将多个 source 对象深度合并为一个新对象。 * * - 后面的 source 优先级更高,会覆盖前面的同名属性 * - 双方都是纯对象的属性会递归合并,而非覆盖 * - 数组合并策略、null 处理和自定义合并函数均可配置 * - 支持 Symbol 键,防止原型污染(跳过 `__proto__` 和 `constructor`) * - 不修改任何输入对象 * * @category Object * @typeParam T 合并结果的对象类型 * @param sources 要合并的源对象数组,后面的对象优先级更高 * @param options 合并行为配置项(可选) * @returns 合并后的新对象 * * @example * ```ts * const defaults = { theme: 'light', pagination: { page: 1, size: 10 } } * const userConfig = { pagination: { size: 20 }, debug: true } * const result = deepMerge([defaults, userConfig]) * // => { theme: 'light', pagination: { page: 1, size: 20 }, debug: true } * ``` * * @example * ```ts * // 数组去重合并 * const result = deepMerge( * [{ tags: ['a', 'b'] }, { tags: ['b', 'c'] }], * { arrayStrategy: 'unique' }, * ) * // => { tags: ['a', 'b', 'c'] } * ``` */ declare function deepMerge(sources: T[], options?: DeepMergeOptions): T; /** * 创建一个预绑定配置的 deepMerge 函数。 * * @category Object * @param options 合并行为配置项 * @returns 预配置的 deepMerge 函数 * * @example * ```ts * const mergeReplace = createDeepMerge({ arrayStrategy: 'replace' }) * const result = mergeReplace([{ tags: ['a'] }, { tags: ['b'] }]) * // => { tags: ['b'] } * ``` */ declare function createDeepMerge(options: DeepMergeOptions): (sources: T[]) => T; type EqualsByPredicate = (a: T, b: T) => boolean; interface EqualsByOptions { /** * 显式等值规则:函数或键路径字符串。 * * - 函数:双方均为对象时直接调用并返回结果,否则视为不等 * - 字符串:双方均为对象时取路径比对,否则视为不等 * - **设置即独占**:命中或失败都不会下落到 `keys` */ by?: string | EqualsByPredicate; /** * 启发式回退候选键。仅在未设置 `by` 且双方均为对象时启用。 * * 按顺序遍历,首个「双方均能取到非空非对象的标量」的键即作为比较依据; * 取不到可用键则返回 `false`,不做深比较。 */ keys?: ReadonlyArray; } /** * 判定两个值是否「等价于同一项」。 * * 比对策略(按优先级): * * 1. 引用相等(含原始值快速路径) * 2. 任一为 `null`/`undefined`:仅当两者完全相等才视为相同 * 3. 双方均为对象时先 `toRaw` 解包,再判引用相等(解决 reactive 包装与其 raw 的等价) * 4. 若 `options.by` 已设置:函数或路径字符串,命中即独占 * 5. 否则若 `options.keys` 已设置:顺序遍历候选键,首个可用标量胜出 * 6. 兜底 `false`,不做结构化深比较 * * @category Object * @typeParam T 比较两侧的值类型 * @param a 比较左侧 * @param b 比较右侧 * @param options 比较行为配置(可选) * @returns 是否视为同一项 * * @example * ```ts * // 1) by 字符串路径:业务对象按主键比对 * equalsBy({ id: 1, name: 'A' }, { id: 1, name: 'B' }, { by: 'id' }) // true * equalsBy({ meta: { id: 1 } }, { meta: { id: 2 } }, { by: 'meta.id' }) // false * ``` * * @example * ```ts * // 2) by 函数:自定义复合等值 * equalsBy( * { tenant: 't1', user: 'u1' }, * { tenant: 't1', user: 'u1' }, * { by: (a, b) => a.tenant === b.tenant && a.user === b.user }, * ) // true * ``` * * @example * ```ts * // 3) keys 启发式回退:v-model 中对象与 items 中对象引用不同但语义相同 * equalsBy( * { label: 'HSL', value: 'hsl' }, * { label: 'HSL', value: 'hsl' }, * { keys: ['value', 'label'] }, * ) // true(首个候选 value 即命中) * ``` */ declare function equalsBy(a: T, b: T, options?: EqualsByOptions): boolean; /** * 预绑定配置的 `equalsBy` 工厂。 * * 方便在 `.filter` / `.some` / 去重等回调中复用同一份比较规则。 * * @category Object * @typeParam T 比较两侧的值类型 * @param options 比较行为配置 * @returns 预配置的二元等值函数 * * @example * ```ts * const sameUser = createEqualsBy<{ id: number }>({ by: 'id' }) * users.some(u => sameUser(u, target)) * ``` */ declare function createEqualsBy(options: EqualsByOptions): (a: T, b: T) => boolean; /** * 从对象中排除指定的键,返回新对象 * * @category Object * @param obj 源对象 * @param keys 要排除的键数组 * @returns 排除指定键后的新对象 * @example * ```ts * const user = { * id: 1, * name: 'John', * password: 'secret', * email: 'john@example.com' * } * * const publicUser = omit(user, ['password']) * console.log(publicUser) // { id: 1, name: 'John', email: 'john@example.com' } * * const basicInfo = omit(user, ['password', 'email']) * console.log(basicInfo) // { id: 1, name: 'John' } * ``` */ declare function omit(obj: T, keys: K[]): OmitByKey; /** * 从对象中排除值为undefined的键 * * @category Object * @param obj 源对象 * @returns 排除undefined值后的新对象 * @example * ```ts * const data = { * name: 'John', * age: undefined, * city: 'New York', * country: undefined * } * * const cleaned = omitUndefined(data) * console.log(cleaned) // { name: 'John', city: 'New York' } * * // 用于API请求前清理数据 * const requestData = omitUndefined({ * title: 'Post Title', * content: 'Post content', * tags: undefined, * published: true * }) * ``` */ declare function omitUndefined(obj: T): Partial; /** * 从对象中选择指定的键,返回新对象 * * @category Object * @param obj 源对象 * @param keys 要选择的键数组 * @returns 只包含指定键的新对象 * @example * ```ts * const user = { * id: 1, * name: 'John', * email: 'john@example.com', * password: 'secret', * createdAt: '2023-01-01', * updatedAt: '2023-01-15' * } * * const publicInfo = pick(user, ['id', 'name', 'email']) * console.log(publicInfo) // { id: 1, name: 'John', email: 'john@example.com' } * * const basicInfo = pick(user, ['id', 'name']) * console.log(basicInfo) // { id: 1, name: 'John' } * ``` */ declare function pick(obj: T, keys: K[]): PickByKey; /** * 将对象按指定键分离为两个对象 * * @category Object * @param obj 源对象 * @param keys 要分离的键数组 * @returns 包含picked和omitted两个对象的结果 * @example * ```ts * const user = { * id: 1, * name: 'John', * email: 'john@example.com', * password: 'secret', * role: 'admin' * } * * const { picked, omitted } = separate(user, ['id', 'name']) * console.log(picked) // { id: 1, name: 'John' } * console.log(omitted) // { email: 'john@example.com', password: 'secret', role: 'admin' } * * // 用于分离敏感信息 * const { picked: publicData, omitted: privateData } = separate(user, ['id', 'name', 'email']) * ``` */ declare function separate(obj: T, keys: K[]): { picked: PickByKey; omitted: OmitByKey; }; /** * 将对象按多分组键集合进行分离(浅层),返回各分组与 others * * - 键冲突策略:先到先得。若同一键出现在多个分组中,则归入第一个匹配到的分组 * - 仅处理对象自有的浅层键,不解析深层路径 * - 分组中包含不存在于对象的键将被忽略 * * @category Object * @param obj 源对象 * @param groups 分组映射,如 { a: ['x', 'y'], b: ['z'] } * @returns 一个对象,包含每个分组的子对象以及 others(其余未被分组捕获的键) * @example * ```ts * const options = { id: 1, name: 'John', email: 'a@b.com', role: 'admin' } * const { a, b, others } = separateMany(options, { a: ['id'], b: ['name'] as const }) * // a: { id: 1 } * // b: { name: 'John' } * // others: { email: 'a@b.com', role: 'admin' } * ``` */ declare function separateMany>(obj: T, groups: M): { [P in keyof M]: PickByKey; } & { others: OmitByKey; }; type PathSegment = string | number; type PathSegments = PathSegment[]; type PathInput = string | PathSegments; /** * 将路径字符串解析为片段数组。 * * - 支持点语法与方括号语法混用 * - 引号键支持单/双引号与反斜杠转义 * - 方括号内未引号的非负整数字面量解析为 number 段 * - 点语法中的纯数字段保持字符串(不转为索引) * * @category Path * @param path 路径字符串或片段数组 * @returns 解析后的片段数组 * @example * ```ts * toPath('a.b[0].c') // ['a', 'b', 0, 'c'] * toPath("a['x.y']") // ['a', 'x.y'] * ``` */ declare function toPath(path: PathInput): PathSegments; /** * 读取对象指定路径的值。 * * - 若取值结果为 undefined,则返回 defaultValue * - 若取值结果为 null,则直接返回 null(不触发默认值) * - 传入空路径时返回 object 本身 * * @category Path * @param object 源对象 * @param path 路径字符串或片段数组 * @param defaultValue 结果为 undefined 时返回的默认值 * @returns 读取到的值或默认值 * @example * ```ts * const obj = { a: { b: { c: 1, d: undefined }, e: null }, arr: [{ x: 9 }] } * getPath(obj, 'a.b.c') // 1 * getPath(obj, 'a.b.d', 42) // 42(d 为 undefined,使用默认值) * getPath(obj, 'a.e', 100) // null(null 不触发默认值) * getPath(obj, 'arr[0].x') // 9 * getPath(obj, '') // 返回 obj 本身 * ``` */ declare function getPath(object: T, path: PathInput, defaultValue?: D): unknown | D; /** * 将片段数组序列化为路径字符串。 * * 规则: * - 合法标识符段使用点拼接(a.b.c) * - 数字段转为索引([0]) * - 其它需要转义的键使用方括号引号(['x.y']),并转义 \\ 与 '\'' * * @category Path * @param segments 路径片段数组 * @returns 路径字符串 * @example * ```ts * const p = joinPath(['a', 'x.y', 0, 'space key']) * // p: "a['x.y'][0]['space key']" * // 与解析往返:toPath(p) => ['a', 'x.y', 0, 'space key'] * ``` */ declare function joinPath(segments: (string | number)[]): string; /** * 在对象指定路径写入值。缺失路径会被自动创建: * - 下一段为 number(索引)时创建数组 * - 下一段为 string(属性)时创建对象 * * 若中途遇到非容器类型(如字符串/数值/布尔),会被替换为正确的容器以继续写入。 * * @category Path * @param object 目标对象(原地修改并返回同一引用) * @param path 路径字符串或片段数组 * @param value 要写入的值 * @returns 原对象(已修改) * @example * ```ts * const obj: any = {} * setPath(obj, 'a.b[0].c', 7) * // obj => { a: { b: [{ c: 7 }] } } * * setPath(obj, 'a.b[2].d', 8) * // 数组自动扩容到长度 3 * // obj.a.b[2] => { d: 8 } * * setPath(obj, 'a.0.b', 1) // 点语法数字键保持为字符串键 * // obj => { a: { 0: { b: 1 } } } * setPath(obj, 'a[0].b', 2) // 索引用方括号 * // obj.a[0].b => 2 * ``` */ declare function setPath>(object: T, path: PathInput, value: unknown): T; /** * 生成字符串的简单哈希值 * * @category Helpers * @param str 待哈希的字符串 * @returns 32位哈希值转换为36进制字符串 * @example * ```ts * const hash1 = simpleHash('hello world') * console.log(hash1) // 'nf5xd4' * * const hash2 = simpleHash('hello world') * console.log(hash1 === hash2) // true,相同字符串产生相同哈希 * * const hash3 = simpleHash('hello world!') * console.log(hash1 === hash3) // false,不同字符串产生不同哈希 * ``` */ declare function simpleHash(str: string): string; /** * 生成随机UUID字符串 * * @category Helpers * @returns 符合UUID v4格式的随机字符串 * @example * ```ts * const id1 = getRandomUUID() * console.log(id1) // 'f47ac10b-58cc-4372-a567-0e02b2c3d479' * * const id2 = getRandomUUID() * console.log(id2) // 'f47ac10b-58cc-4372-a567-0e02b2c3d480' * * // 用于生成唯一标识符 * const componentId = `component-${getRandomUUID()}` * ``` */ declare function getRandomUUID(): string; type MinimarkAttributeValue = unknown; type MinimarkAttributes = Record; /** * Minimark-like AST 节点。 * * 字符串节点表示文本内容,元组节点使用 `[tag, attributes, ...children]` * 结构表示元素。 */ type MinimarkNode = string | [tag: string, attributes: MinimarkAttributes, ...children: MinimarkNode[]]; /** * 包含根节点列表的 Minimark-like 文档主体。 */ interface MinimarkDocument { value: MinimarkNode[]; } /** * 将 Minimark-like AST 子集序列化为 Markdown。 * * 支持的节点会输出 Markdown,不支持的标签会回退为 HTML。 * 该函数不是 `minimark.stringify()` 的字节级等价替代。 * * @param body - 要序列化的 Minimark-like 文档主体。 * @returns 带 HTML fallback 的 Markdown,并以单个换行结尾。 * * @example * ```ts * stringifyMinimark({ * value: [ * ['h1', {}, 'Title'], * ['p', {}, 'Hello ', ['strong', {}, 'world']], * ], * }) * // "# Title\n\nHello **world**\n" * ``` */ declare function stringifyMinimark(body: MinimarkDocument): string; /** * 将对象的键名转换为kebab-case格式 * * @category Object * @param obj 待转换的对象 * @param deep 是否深度转换嵌套对象,默认为false * @returns 转换后的对象 * @example * ```ts * const obj = { * firstName: 'John', * lastName: 'Doe', * userInfo: { * birthDate: '1990-01-01', * phoneNumber: '123-456-7890' * } * } * * const converted = convertToKebabCase(obj) * console.log(converted) * // { * // 'first-name': 'John', * // 'last-name': 'Doe', * // 'user-info': { birthDate: '1990-01-01', phoneNumber: '123-456-7890' } * // } * * const deepConverted = convertToKebabCase(obj, true) * console.log(deepConverted) * // { * // 'first-name': 'John', * // 'last-name': 'Doe', * // 'user-info': { 'birth-date': '1990-01-01', 'phone-number': '123-456-7890' } * // } * ``` */ declare function convertToKebabCase(obj: T, deep?: boolean): T; /** * 将字符串转换为驼峰命名格式(第一个单词小写,后续单词首字母大写)。 * * @category String * @param str 要转换的字符串 * @returns 驼峰命名格式的字符串 * @example * ```ts * camelCase('First Name') // 'firstName' * camelCase('first_name') // 'firstName' * camelCase('first-name') // 'firstName' * camelCase('XMLHttpRequest') // 'xmlHttpRequest' * ``` */ declare function camelCase(str: string): string; /** * 将字符串首字母大写,其余字母小写。 * * @category String * @param str 要转换的字符串 * @returns 首字母大写的字符串 * @example * ```ts * capitalize('hello') // 'Hello' * capitalize('HELLO') // 'Hello' * capitalize('hello world') // 'Hello world' * ``` */ declare function capitalize(str: string): string; /** * 将字符串转换为短横线命名格式(kebab-case)。 * * @category String * @param str 要转换的字符串 * @returns 短横线命名格式的字符串 * @example * ```ts * kebabCase('firstName') // 'first-name' * kebabCase('First Name') // 'first-name' * kebabCase('first_name') // 'first-name' * kebabCase('XMLHttpRequest') // 'xml-http-request' * ``` */ declare function kebabCase(str: string): string; /** * 将字符串转换为小写格式,单词之间用空格分隔。 * * @category String * @param str 要转换的字符串 * @returns 小写格式的字符串 * @example * ```ts * lowerCase('firstName') // 'first name' * lowerCase('First_Name') // 'first name' * lowerCase('FIRST-NAME') // 'first name' * lowerCase('XMLHttpRequest') // 'xml http request' * ``` */ declare function lowerCase(str: string): string; /** * 将字符串首字母小写,其余字母保持原样。 * * @category String * @param str 要转换的字符串 * @returns 首字母小写的字符串 * @example * ```ts * lowerFirst('Hello') // 'hello' * lowerFirst('HELLO') // 'hELLO' * lowerFirst('Hello World') // 'hello World' * ``` */ declare function lowerFirst(str: string): string; /** * 将字符串转换为帕斯卡命名格式(PascalCase,每个单词首字母大写)。 * * @category String * @param str 要转换的字符串 * @returns 帕斯卡命名格式的字符串 * @example * ```ts * pascalCase('firstName') // 'FirstName' * pascalCase('first_name') // 'FirstName' * pascalCase('first-name') // 'FirstName' * pascalCase('XMLHttpRequest') // 'XmlHttpRequest' * ``` */ declare function pascalCase(str: string): string; /** * 将字符串转换为下划线命名格式(snake_case)。 * * @category String * @param str 要转换的字符串 * @returns 下划线命名格式的字符串 * @example * ```ts * snakeCase('firstName') // 'first_name' * snakeCase('First Name') // 'first_name' * snakeCase('first-name') // 'first_name' * snakeCase('XMLHttpRequest') // 'xml_http_request' * ``` */ declare function snakeCase(str: string): string; /** * 高亮片段,`match` 标记该片段是否命中关键字。 */ interface HighlightSegment { text: string; match: boolean; } /** * 按关键字将文本切分为命中/未命中片段,便于渲染高亮。 * * 匹配不区分大小写,命中片段保留原始大小写;关键字为空或文本不含关键字时返回整段未命中。 * * @category String * @param text 源文本 * @param term 关键字 * @returns 片段数组,依次拼接即为原文本 * @example * ```ts * splitHighlight('ABC', 'b') * // [{ text: 'A', match: false }, { text: 'B', match: true }, { text: 'C', match: false }] * ``` */ declare function splitHighlight(text: string, term: string): HighlightSegment[]; /** * 将字符串转换为Start Case格式(每个单词首字母大写,用空格分隔)。 * * @category String * @param str 要转换的字符串 * @returns Start Case格式的字符串 * @example * ```ts * startCase('firstName') // 'First Name' * startCase('first_name') // 'First Name' * startCase('first-name') // 'First Name' * startCase('XMLHttpRequest') // 'XML Http Request' * ``` */ declare function startCase(str: string): string; /** * 将字符串转换为大写格式,单词之间用空格分隔。 * * @category String * @param str 要转换的字符串 * @returns 大写格式的字符串 * @example * ```ts * upperCase('firstName') // 'FIRST NAME' * upperCase('first_name') // 'FIRST NAME' * upperCase('first-name') // 'FIRST NAME' * upperCase('XMLHttpRequest') // 'XML HTTP REQUEST' * ``` */ declare function upperCase(str: string): string; /** * 将字符串首字母大写,其余字母保持原样。 * * @category String * @param str 要转换的字符串 * @returns 首字母大写的字符串 * @example * ```ts * upperFirst('hello') // 'Hello' * upperFirst('hELLO') // 'HELLO' * upperFirst('hello world') // 'Hello world' * ``` */ declare function upperFirst(str: string): string; /** * 将字符串分解为单词数组。支持camelCase、snake_case、kebab-case等各种命名风格。 * * @category String * @param str 要分解的字符串 * @returns 单词数组 * @example * ```ts * words('helloWorld') // ['hello', 'World'] * words('hello_world') // ['hello', 'world'] * words('hello-world') // ['hello', 'world'] * words('XMLHttpRequest') // ['XML', 'Http', 'Request'] * ``` */ declare function words(str: string): string[]; /** * 树节点类型定义 * * @template T 节点数据类型 */ type TreeNode = T & { children?: TreeNode[]; [key: string]: any; }; /** * 树形配置类型 */ interface TreeConfig { id: string; pid: string; children: string; } /** * 树形配置输入类型 */ type TreeConfigInput = Partial; /** * 树统计信息类型 */ interface TreeStats { total: number; leaves: number; depth: number; branches: number; } /** * 树节点谓词函数类型 * * @template T 节点数据类型 * @param params 包含节点信息的对象参数 * @param params.node 当前节点 * @param params.depth 节点深度(从0开始) * @param params.path 从根节点到当前节点的路径数组 * @param params.index 节点在同级节点中的索引 * @returns 是否满足条件 */ type TreePredicate = (params: { node: TreeNode; depth: number; path: readonly TreeNode[]; index: number; }) => boolean; /** * 树节点转换函数类型 * * @template T 源节点数据类型 * @template R 目标节点数据类型 * @param params 包含节点信息的对象参数 * @param params.node 当前节点 * @param params.depth 节点深度(从0开始) * @param params.path 从根节点到当前节点的路径数组 * @param params.index 节点在同级节点中的索引 * @returns 转换后的节点数据 */ type TreeTransformer = (params: { node: TreeNode; depth: number; path: readonly TreeNode[]; index: number; }) => R; /** * 树节点访问函数类型 * * @template T 节点数据类型 * @param params 包含节点信息的对象参数 * @param params.node 当前节点 * @param params.depth 节点深度(从0开始) * @param params.path 从根节点到当前节点的路径数组 * @param params.index 节点在同级节点中的索引 * @returns 返回false可以终止遍历或跳过子节点 */ type TreeVisitor = (params: { node: TreeNode; depth: number; path: readonly TreeNode[]; index: number; }) => void | boolean; /** * 从扁平数组创建树形结构 * * @category Tree * @param list 扁平数组数据 * @param config 树形配置选项 * @returns 树形结构数组 * @example * ```ts * const flatData = [ * { id: '1', name: '部门1', parentId: null }, * { id: '2', name: '部门1-1', parentId: '1' }, * { id: '3', name: '部门1-2', parentId: '1' }, * { id: '4', name: '部门1-1-1', parentId: '2' } * ] * * const tree = fromList(flatData, { * id: 'id', * pid: 'parentId', * children: 'children' * }) * * console.log(tree) // 转换为树形结构 * ``` */ declare function fromList(list: T[], config?: TreeConfigInput): TreeNode[]; /** * 将树形结构转换为扁平数组 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param config 树形配置选项 * @returns 扁平数组 * @example * ```ts * const tree = [ * { * id: '1', * name: '根节点', * children: [ * { id: '2', name: '子节点1', children: [] }, * { id: '3', name: '子节点2', children: [] } * ] * } * ] * * const flatList = toList(tree) * console.log(flatList) // [{ id: '1', name: '根节点' }, { id: '2', name: '子节点1' }, ...] * ``` */ declare function toList(tree: TreeNode | TreeNode[], config?: TreeConfigInput): T[]; /** * 估算树形结构的节点数量 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param config 树形配置选项 * @returns 节点总数量 * @example * ```ts * const tree = [ * { * id: '1', * name: '根节点', * children: [ * { id: '2', name: '子节点1', children: [] }, * { id: '3', name: '子节点2', children: [] } * ] * } * ] * * const size = estimateSize(tree) * console.log(size) // 3 * ``` */ declare function estimateSize(tree: TreeNode | TreeNode[], config?: TreeConfigInput): number; /** * 在指定节点前插入新节点 * * @category Tree * @param tree 树形结构数组 * @param targetId 目标节点的ID * @param newNode 要插入的新节点数据 * @param config 树形配置选项 * @returns 是否成功插入 * @example * ```ts * const tree = [ * { * id: '1', * name: '节点1', * children: [ * { id: '2', name: '节点2', children: [] } * ] * } * ] * * const success = insertBefore(tree, '2', { id: '1.5', name: '新节点' }) * console.log(success) // true * ``` */ declare function insertBefore(tree: TreeNode[], targetId: string, newNode: T, config?: TreeConfigInput): boolean; /** * 在指定节点后插入新节点 * * @category Tree * @param tree 树形结构数组 * @param targetId 目标节点的ID * @param newNode 要插入的新节点数据 * @param config 树形配置选项 * @returns 是否成功插入 * @example * ```ts * const tree = [ * { * id: '1', * name: '节点1', * children: [ * { id: '2', name: '节点2', children: [] } * ] * } * ] * * const success = insertAfter(tree, '2', { id: '3', name: '新节点' }) * console.log(success) // true * ``` */ declare function insertAfter(tree: TreeNode[], targetId: string, newNode: T, config?: TreeConfigInput): boolean; /** * 从树中删除指定节点 * * @category Tree * @param tree 树形结构数组 * @param targetId 要删除的节点ID * @param config 树形配置选项 * @returns 被删除的节点,未找到时返回undefined * @example * ```ts * const tree = [ * { * id: '1', * name: '根节点', * children: [ * { id: '2', name: '子节点', children: [] } * ] * } * ] * * const removed = remove(tree, '2') * console.log(removed?.name) // '子节点' * ``` */ declare function remove(tree: TreeNode[], targetId: string, config?: TreeConfigInput): TreeNode | undefined; /** * 查找树中第一个满足条件的节点 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param predicate 查找条件函数 * @param config 树形配置选项 * @returns 匹配的节点;未找到时返回undefined * @example * ```ts * const tree = [ * { * id: '1', * name: '部门1', * children: [ * { id: '2', name: '部门1-1', children: [] } * ] * } * ] * * const result = find(tree, ({ node }) => node.name === '部门1-1') * console.log(result?.id) // '2' * ``` */ declare function find(tree: TreeNode | TreeNode[], predicate: TreePredicate, config?: TreeConfigInput): TreeNode | undefined; /** * 查找树中所有满足条件的节点 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param predicate 查找条件函数 * @param config 树形配置选项 * @returns 所有匹配的节点数组 * @example * ```ts * const tree = [ * { * id: '1', * type: 'folder', * name: '根目录', * children: [ * { id: '2', type: 'file', name: '文件1', children: [] }, * { id: '3', type: 'file', name: '文件2', children: [] } * ] * } * ] * * const files = findAll(tree, ({ node }) => node.type === 'file') * console.log(files.length) // 2 * ``` */ declare function findAll(tree: TreeNode | TreeNode[], predicate: TreePredicate, config?: TreeConfigInput): TreeNode[]; /** * 根据ID查找树中的节点 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param id 要查找的节点ID * @param config 树形配置选项 * @returns 匹配的节点;未找到时返回undefined * @example * ```ts * const tree = [ * { * id: '1', * name: '根节点', * children: [ * { id: '2', name: '子节点', children: [] } * ] * } * ] * * const result = findById(tree, '2') * console.log(result?.name) // '子节点' * ``` */ declare function findById(tree: TreeNode | TreeNode[], id: string, config?: TreeConfigInput): TreeNode | undefined; /** * 过滤树形结构,保留满足条件的节点及其祖先和后代 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param predicate 过滤条件函数,接收对象参数 {node, depth, path, index} * @param config 树形配置选项 * @returns 过滤后的树形结构数组 * @example * ```ts * const tree = [ * { * id: '1', * type: 'folder', * name: '根目录', * children: [ * { id: '2', type: 'file', name: '文档.txt', children: [] }, * { id: '3', type: 'folder', name: '子目录', children: [ * { id: '4', type: 'file', name: '图片.jpg', children: [] } * ] } * ] * } * ] * * const filtered = filter(tree, ({ node }) => node.type === 'file') * // 返回包含所有文件节点及其父级路径的树结构 * ``` */ declare function filter(tree: TreeNode | TreeNode[], predicate: TreePredicate, config?: TreeConfigInput): TreeNode[]; /** * 转换树形结构,将每个节点转换为新的结构 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param transformer 节点转换函数,接收对象参数 {node, depth, path, index} * @param config 树形配置选项 * @returns 转换后的树形结构数组 * @example * ```ts * const tree = [ * { * id: '1', * name: '部门1', * children: [ * { id: '2', name: '部门1-1', children: [] } * ] * } * ] * * const transformed = transform(tree, ({ node, depth }) => ({ * key: node.id, * title: node.name, * level: depth * })) * // 转换为新的数据结构 * ``` */ declare function transform(tree: TreeNode | TreeNode[], transformer: TreeTransformer, config?: TreeConfigInput): TreeNode[]; /** * 遍历树形结构的每个节点 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param visitor 访问者函数,接收对象参数 {node, depth, path, index},返回false可以跳过子节点的遍历 * @param config 树形配置选项 * @example * ```ts * const tree = [ * { * id: '1', * name: '根节点', * children: [ * { id: '2', name: '子节点', children: [] } * ] * } * ] * * forEach(tree, ({ node, depth }) => { * console.log(`${' '.repeat(depth * 2)}${node.name}`) * // 输出缩进的树结构 * }) * ``` */ declare function forEach(tree: TreeNode | TreeNode[], visitor: TreeVisitor, config?: TreeConfigInput): void; /** * 按 id 不可变地更新树中的节点 * * 定位 `node[config.id] === targetId` 的节点,以 `updater` 返回的新节点替换之, * 仅重建从根到目标的路径,未触及的分支保持原引用;未命中时原样返回同一棵树。 * * @category Tree * @param tree 树形结构数组 * @param targetId 目标节点的 ID * @param updater 节点更新函数,接收对象参数 {node, depth, path, index},返回替换后的节点 * @param config 树形配置选项 * @returns 更新后的新树;未命中时返回原树 * @example * ```ts * const tree = [{ id: '1', children: [{ id: '2', name: '旧' }] }] * const next = updateNode(tree, '2', ({ node }) => ({ ...node, name: '新' })) * // tree 不变,next[0].children[0].name === '新' * ``` */ declare function updateNode(tree: TreeNode[], targetId: string, updater: TreeTransformer, config?: TreeConfigInput): TreeNode[]; /** * 获取树形结构的统计信息 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param config 树形配置选项 * @returns 树的统计信息,包含总节点数、叶子节点数、最大深度和分支节点数 * @example * ```ts * const tree = [ * { * id: '1', * name: '根节点', * children: [ * { id: '2', name: '子节点1', children: [] }, * { id: '3', name: '子节点2', children: [ * { id: '4', name: '孙节点', children: [] } * ] } * ] * } * ] * * const stats = getStats(tree) * console.log(stats) // { total: 4, leaves: 2, depth: 3, branches: 2 } * ``` */ declare function getStats(tree: TreeNode | TreeNode[], config?: TreeConfigInput): TreeStats; /** * 验证树形结构的有效性 * * @category Tree * @param tree 树形结构(单个节点或节点数组) * @param config 树形配置选项 * @returns 验证结果,包含是否有效和错误信息数组 * @example * ```ts * const tree = [ * { * id: '1', * name: '根节点', * children: [ * { id: '2', name: '子节点', children: [] } * ] * } * ] * * const result = validate(tree) * console.log(result.isValid) // true * console.log(result.errors) // [] * ``` */ declare function validate(tree: TreeNode | TreeNode[], config?: TreeConfigInput): { isValid: boolean; errors: string[]; }; /** * 树形数据结构操作工具类 * * 提供了一系列操作树形数据的静态方法,包括: * - 查找:find, findAll, findById * - 转换:fromList, toList, transform * - 过滤:filter * - 遍历:forEach * - 统计:estimateSize, getStats * - 修改:insertBefore, insertAfter, remove * - 验证:validate * * 所有使用谓词函数或访问函数的方法都采用对象解构参数格式: * `({ node, depth, path, index }) => boolean` * * @example * ```ts * // 1. 从扁平数组创建树形结构 * const departments = [ * { id: '1', name: '技术部', parentId: null }, * { id: '2', name: '前端组', parentId: '1' }, * { id: '3', name: '后端组', parentId: '1' }, * { id: '4', name: 'UI 组', parentId: '2' }, * { id: '5', name: '测试组', parentId: '2' } * ] * * const tree = Tree.fromList(departments, { * id: 'id', * pid: 'parentId', * children: 'children' * }) * * // 2. 查找节点 * const frontend = Tree.find(tree, ({ node }) => node.name === '前端组') * console.log(frontend) // { id: '2', name: '前端组', children: [...] } * * const uiNode = Tree.findById(tree, '4') * console.log(uiNode) // { id: '4', name: 'UI 组', ... } * * // 3. 查找所有叶子节点 * const leaves = Tree.findAll(tree, ({ node }) => { * return !node.children || node.children.length === 0 * }) * console.log(leaves) // [{ id: '4', ... }, { id: '5', ... }, { id: '3', ... }] * * // 4. 过滤节点(保留匹配节点及其祖先) * const filtered = Tree.filter(tree, ({ node }) => node.name.includes('组')) * // 返回包含所有 "组" 节点及其父级路径的树结构 * * // 5. 转换节点结构 * const menuTree = Tree.transform(tree, ({ node, depth }) => ({ * key: node.id, * label: node.name, * level: depth, * indent: depth * 20 * })) * * // 6. 遍历所有节点 * Tree.forEach(tree, ({ node, depth, path }) => { * const indent = ' '.repeat(depth) * const breadcrumb = path.map(n => n.name).join(' > ') * console.log(`${indent}${node.name} (路径: ${breadcrumb})`) * }) * * // 7. 修改树结构 * Tree.insertBefore(tree, '3', { id: '6', name: '运维组' }) * Tree.insertAfter(tree, '2', { id: '7', name: '移动组' }) * const removed = Tree.remove(tree, '5') * * // 8. 获取统计信息 * const stats = Tree.getStats(tree) * console.log(stats) * // { total: 5, leaves: 3, depth: 3, branches: 2 } * * // 9. 验证树结构 * const validation = Tree.validate(tree) * if (!validation.isValid) { * console.error('树结构错误:', validation.errors) * } * * // 10. 转换回扁平数组 * const flatList = Tree.toList(tree) * console.log(flatList) // [{ id: '1', name: '技术部' }, ...] * ``` */ declare class Tree { static fromList: typeof fromList; static toList: typeof toList; static estimateSize: typeof estimateSize; static find: typeof find; static findAll: typeof findAll; static findById: typeof findById; static insertBefore: typeof insertBefore; static insertAfter: typeof insertAfter; static remove: typeof remove; static filter: typeof filter; static transform: typeof transform; static updateNode: typeof updateNode; static forEach: typeof forEach; static getStats: typeof getStats; static validate: typeof validate; } /** * 统一同步/异步返回类型 * @typeParam T - 类型 * @example * // type T = string | Promise * // type R = ApiAwaitable * // 结果:R 为 string | Promise */ type ApiAwaitable = T | Promise; /** * 同步或异步的无返回值回调 * * @example * ```ts * const onMounted: VoidCallback = () => doSomething() * const onLoad: VoidCallback = async () => { await fetchData() } * ``` */ type VoidCallback = () => ApiAwaitable; /** * 提取Promise类型 * @typeParam T - 类型 * @example * // type T = Promise * // type R = ApiUnwrapPromise * // 结果:R 为 string */ type ApiUnwrapPromise = T extends Promise ? U : T; /** * 提取函数返回类型 * @typeParam TFn - 函数类型 * @example * // type Fn = (x: number, y: string) => Promise * // type R = ApiAwaitedReturn * // 结果:R 为 string */ type ApiAwaitedReturn = TFn extends (...args: any[]) => ApiAwaitable ? R : never; /** * 提供字面量提示的同时允许任意同类原始值 * * @example * ```ts * type Color = Suggest<'red' | 'blue'> // 'red' | 'blue' | (string & {}) * type Status = Suggest<200 | 404> // 200 | 404 | (number & {}) * type Mixed = Suggest<'a' | 1> // 'a' | 1 | (string & {}) | (number & {}) * * const color1: Color = 'red' // 有提示 * const color2: Color = 'yellow' // 也允许 * ``` */ type Suggest = T | (T extends string ? string & {} : never) | (T extends number ? number & {} : never) | (T extends bigint ? bigint & {} : never); /** * 允许值 T 或一个返回 T 的函数;显式传入 Ctx 时回调会接收上下文参数 * * @template T - 值类型 * @template Ctx - 上下文类型,省略时回调为无参函数 * * @example * ```ts * type A = MaybeFn // string | (() => string) * type B = MaybeFn // string | ((ctx: Context) => string) * * const a1: A = 'static' * const a2: A = () => 'computed' * const b1: B = 'static' * const b2: B = ctx => ctx.dynamicValue * ``` */ type MaybeFn = [Ctx] extends [never] ? T | (() => T) : T | ((ctx: Ctx) => T); /** * 响应式值类型 - 基于 Vue 的 `MaybeRefOrGetter` 扩展,额外支持上下文回调 * * @template T - 值类型 * @template CTX - 上下文类型(用于回调函数) * * @example * ```ts * const value: ReactiveValue = ref(false) * const getter: ReactiveValue = () => name.value * const computed: ReactiveValue = computed(() => count.value) * const withContext: ReactiveValue = (ctx) => ctx.value > 0 * ``` */ type ReactiveValue = [CTX] extends [never] ? MaybeRefOrGetter : MaybeRefOrGetter | ((ctx: CTX) => T); type StripNullable = T extends null | undefined ? never : T; /** * 检测类型 T 是否为 `any` * * 利用 `any` 会穿透类型运算的特性(`1 & any` 为 `any`,`0 extends any` 为 `true`)实现检测。 * * @example * ```ts * type A = IsAny // true * type B = IsAny // false * type C = IsAny // false * type D = IsAny // false * ``` */ type IsAny = 0 extends (1 & T) ? true : false; /** * 将字面量类型宽化为其对应的基础类型,同时保留可选性(`undefined`)。 * * - `any` → 保持原样 * - `undefined | never` → `unknown` * - `boolean` 字面量 → `boolean` * - `string` 字面量 → `string` * - 其他类型 → 保持原样 * * 主要用于工厂方法的 props 推断,防止 SFC 泛型默认参数产生的字面量类型污染调用签名。 * * @example * ```ts * type A = WidenLiteral<'hello'> // string * type B = WidenLiteral // boolean * type C = WidenLiteral<'foo' | undefined> // string | undefined * type D = WidenLiteral // number * ``` */ type WidenLiteral = IsAny extends true ? T : [NonNullable] extends [never] ? unknown : NonNullable extends boolean ? boolean | Extract : NonNullable extends string ? string | Extract : T; interface ParsedUrl { /** 完整的原始 URL */ href: string; /** 协议 (http:, https:, etc.) */ protocol: string; /** 主机名 + 端口 */ host: string; /** 主机名 */ hostname: string; /** 端口号 */ port: string; /** 路径部分 */ pathname: string; /** 查询字符串 (包含 ?) */ search: string; /** 哈希部分 (包含 #) */ hash: string; /** 用户认证信息 (user:pass) */ auth: string; /** 源 (protocol + host) */ origin: string; } /** * 查询参数值类型 */ type QueryParamValue = string | number | boolean | null | undefined; /** * 查询参数对象类型 */ type QueryParams = Record; /** * 增强版组件类型提取,支持泛型 SFC 的三种 vue-tsc 编译签名模式: * - 模式 A:函数参数可直接解析 → Parameters[0] * - 模式 A':参数自引用(返回 any)→ 返回值 __ctx 成员 * - 模式 B:DefineComponent 包装 → InstanceType['$props'] */ type IsComponent = StringOrVNode | Component | DefineComponent | ((...args: any[]) => any); type ComponentType = T extends new (...args: any) => {} ? 1 : T extends (...args: any) => any ? 2 : 0; /** 检测 any 类型 */ type _IsAny = 0 extends (1 & T) ? true : false; /** 从构造器组件提取 InstanceType 成员,映射展平避免 TS 延迟求值 */ type _InstanceTypeMember = T extends abstract new (...args: any) => infer I ? K extends keyof I ? { [P in keyof I[K]]: I[K][P]; } : never : never; /** 从可调用组件提取第一个参数(props),排除 any/never */ type _FnParam = T extends (...args: any) => any ? [Parameters[0]] extends [never] ? never : _IsAny[0]> extends true ? never : Parameters[0] : never; /** 从可调用组件的 ctx 参数提取指定成员(slots/attrs/emit) */ type _FnCtxMember = T extends (props: any, ctx: infer Ctx, ...args: any) => any ? Ctx extends Record ? NonNullable : never : never; /** 从返回值 __ctx 提取指定字段(模式 A':参数自引用时 __ctx 仍可解析) */ type _ReturnCtxMember = T extends (...args: any) => infer R ? R extends { __ctx?: infer Ctx; } ? Ctx extends Record ? _IsAny extends true ? never : { [P in keyof M]: M[P]; } : never : never : never; /** * 组件 Props 提取 * - 模式 A → Parameters[0] * - 模式 A' → __ctx.props * - 模式 B → $props * - 回退 → {} */ type ComponentProps = _FnParam extends never ? _ReturnCtxMember extends never ? _InstanceTypeMember extends never ? {} : NonNullable<_InstanceTypeMember> : NonNullable<_ReturnCtxMember> : _FnParam; /** * 组件 Slots 提取 * - 模式 A → ctx.slots * - 模式 A' → __ctx.slots * - 模式 B → $slots * - 回退 → {} */ type ComponentSlots = _IsAny<_FnCtxMember> extends true ? _ReturnCtxMember extends never ? _InstanceTypeMember extends never ? {} : NonNullable<_InstanceTypeMember> : _ReturnCtxMember : [_FnCtxMember] extends [never] ? _ReturnCtxMember extends never ? _InstanceTypeMember extends never ? {} : NonNullable<_InstanceTypeMember> : _ReturnCtxMember : _FnCtxMember; /** * 组件 Attrs 提取 * - 模式 A → ctx.attrs * - 模式 A' → __ctx.attrs * - 模式 B → $attrs * - 回退 → {} */ type ComponentAttrs = _IsAny<_FnCtxMember> extends true ? _ReturnCtxMember extends never ? _InstanceTypeMember extends never ? {} : NonNullable<_InstanceTypeMember> : _ReturnCtxMember : [_FnCtxMember] extends [never] ? _ReturnCtxMember extends never ? _InstanceTypeMember extends never ? {} : NonNullable<_InstanceTypeMember> : _ReturnCtxMember : _FnCtxMember; /** * 组件 Emit 提取 * - 模式 A → ctx.emit * - 模式 A' → __ctx.emit * - 模式 B → $emit * - 回退 → {} */ type ComponentEmit = _IsAny<_FnCtxMember> extends true ? _ReturnCtxMember extends never ? _InstanceTypeMember extends never ? {} : NonNullable<_InstanceTypeMember> : _ReturnCtxMember : [_FnCtxMember] extends [never] ? _ReturnCtxMember extends never ? _InstanceTypeMember extends never ? {} : NonNullable<_InstanceTypeMember> : _ReturnCtxMember : _FnCtxMember; /** * 组件 Exposed 提取 * - 构造器 → InstanceType * - 可调用 → expose 参数 * - 回退 → {} */ type ComponentExposed = T extends new (...args: any) => infer E ? E : T extends (props: any, ctx: any, expose: (exposed: infer E) => any, ...args: any) => any ? NonNullable : {}; /** * 将数组分割成指定大小的块 * * @category Array * @param arr 待分割的数组 * @param size 每个块的大小 * @returns 分割后的二维数组 * @example * ```ts * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] * const chunks = chunk(numbers, 3) * console.log(chunks) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]] * * const names = ['Alice', 'Bob', 'Charlie', 'David', 'Eve'] * const pairs = chunk(names, 2) * console.log(pairs) // [['Alice', 'Bob'], ['Charlie', 'David'], ['Eve']] * ``` */ declare function chunk(arr: T[], size: number): T[][]; /** * 数组扁平化,将嵌套数组展平到指定深度 * * @category Array * @param arr 待扁平化的数组 * @param depth 扁平化深度,默认为1 * @returns 扁平化后的数组 * @example * ```ts * const nested = [1, [2, 3], [4, [5, 6]]] * const flat1 = flatten(nested) * console.log(flat1) // [1, 2, 3, 4, [5, 6]] * * const flat2 = flatten(nested, 2) * console.log(flat2) // [1, 2, 3, 4, 5, 6] * ``` */ declare function flatten(arr: T[], depth?: number): any[]; /** * 数组去重,返回去除重复元素后的新数组 * * @category Array * @param arr 待去重的数组 * @returns 去重后的新数组 * @example * ```ts * const numbers = [1, 2, 2, 3, 3, 4] * const uniqueNumbers = unique(numbers) * console.log(uniqueNumbers) // [1, 2, 3, 4] * * const strings = ['a', 'b', 'a', 'c'] * const uniqueStrings = unique(strings) * console.log(uniqueStrings) // ['a', 'b', 'c'] * ``` */ declare function unique(arr: T[]): T[]; /** * 防抖函数,在指定时间内多次触发只执行最后一次 * * @category Async * @param func 需要防抖的函数 * @param wait 防抖延迟时间(毫秒) * @returns 防抖处理后的函数 * @example * ```ts * const debouncedSearch = debounce((query: string) => { * console.log('搜索:', query) * }, 300) * * // 连续调用,只有最后一次会执行 * debouncedSearch('a') * debouncedSearch('ab') * debouncedSearch('abc') // 只有这次会在300ms后执行 * ``` */ declare function debounce any>(func: T, wait: number): (...args: Parameters) => void; /** * 延迟执行函数,返回一个在指定时间后resolve的Promise * * @category Async * @param ms 延迟时间(毫秒) * @returns 延迟Promise * @example * ```ts * // 延迟1秒后继续执行 * await sleep(1000) * console.log('1秒后执行') * * // 在异步函数中使用 * async function delayedOperation() { * console.log('开始') * await sleep(500) * console.log('500ms后执行') * } * ``` */ declare function sleep(ms: number): Promise; /** * 可取消的延迟函数,返回Promise和取消函数 * * @category Async * @param ms 延迟时间(毫秒) * @returns 包含Promise和取消函数的对象 * @example * ```ts * const { promise, cancel } = sleepWithCancel(5000) * * // 在另一个地方取消延迟 * setTimeout(() => { * cancel() // 取消延迟 * }, 2000) * * try { * await promise * console.log('5秒后执行') * } catch (error) { * console.log('延迟被取消') * } * ``` */ declare function sleepWithCancel(ms: number): { promise: Promise; cancel: () => void; }; /** * 节流函数,在指定时间内多次触发只执行第一次 * * @category Async * @param func 需要节流的函数 * @param limit 节流时间间隔(毫秒) * @returns 节流处理后的函数 * @example * ```ts * const throttledScroll = throttle((event: Event) => { * console.log('滚动事件处理') * }, 100) * * // 监听滚动事件,每100ms最多执行一次 * window.addEventListener('scroll', throttledScroll) * ``` */ declare function throttle any>(func: T, limit: number): (...args: Parameters) => void; /** * 把 CSS 长度字符串折算为像素 * * 支持 `px` / `rem` / `em`,rem/em 按 16 折算;无单位视为 px;无法识别时回退到 fallback。 * * @category Css * @param value CSS 长度字符串,如 `'16px'`、`'1rem'`、`'2.5em'` * @param fallback 回退像素值,默认 16 * @returns 折算后的像素数值 * @example * ```ts * lengthToPx('1rem') // 16 * lengthToPx('24px') // 24 * lengthToPx('2.5em') // 40 * lengthToPx('auto') // 16 (fallback) * lengthToPx('', 0) // 0 (custom fallback) * ``` */ declare function lengthToPx(value: string, fallback?: number): number; /** * 从左到右组合函数:前一个的返回值作为后一个的入参 * * 首个函数可接收多个参数,其后逐个单参串联。超过 8 个函数时类型退化为同签名 * 变参形态,运行时行为不变;未传入任何函数时返回恒等函数。 * * @category Function * @param fn1 起始函数,其后每个函数依次接收上一个的返回值 * @returns 组合后的函数 * @example * ```ts * const parse = pipe( * (v: string) => v.trim(), * (v: string) => Number(v), * (v: number) => Math.round(v), * ) * parse(' 4.6 ') // 5 * ``` * @example * ```ts * // 同签名场景:把多个互不相干的 reducer 合成一条链 * const chained = pipe(highlight, fade, filter) * chained(attrs) * ``` */ declare function pipe(fn1: (...args: A) => R1): (...args: A) => R1; declare function pipe(fn1: (...args: A) => R1, fn2: (value: R1) => R2): (...args: A) => R2; declare function pipe(fn1: (...args: A) => R1, fn2: (value: R1) => R2, fn3: (value: R2) => R3): (...args: A) => R3; declare function pipe(fn1: (...args: A) => R1, fn2: (value: R1) => R2, fn3: (value: R2) => R3, fn4: (value: R3) => R4): (...args: A) => R4; declare function pipe(fn1: (...args: A) => R1, fn2: (value: R1) => R2, fn3: (value: R2) => R3, fn4: (value: R3) => R4, fn5: (value: R4) => R5): (...args: A) => R5; declare function pipe(fn1: (...args: A) => R1, fn2: (value: R1) => R2, fn3: (value: R2) => R3, fn4: (value: R3) => R4, fn5: (value: R4) => R5, fn6: (value: R5) => R6): (...args: A) => R6; declare function pipe(fn1: (...args: A) => R1, fn2: (value: R1) => R2, fn3: (value: R2) => R3, fn4: (value: R3) => R4, fn5: (value: R4) => R5, fn6: (value: R5) => R6, fn7: (value: R6) => R7): (...args: A) => R7; declare function pipe(fn1: (...args: A) => R1, fn2: (value: R1) => R2, fn3: (value: R2) => R3, fn4: (value: R3) => R4, fn5: (value: R4) => R5, fn6: (value: R5) => R6, fn7: (value: R6) => R7, fn8: (value: R7) => R8): (...args: A) => R8; declare function pipe(): (value: T) => T; declare function pipe(...fns: Array<(value: T) => T>): (value: T) => T; /** * 将数值钳制到闭区间内 * * `min` 大于 `max` 时静默交换两端,因此调用方无需保证入参顺序;`value` 为 `NaN` 时返回 `NaN`。 * * @category Math * @param value 待钳制的数值 * @param min 区间一端 * @param max 区间另一端 * @returns 落入区间内的数值 * @example * ```ts * clamp(15, 0, 10) // 10 * clamp(-5, 0, 10) // 0 * clamp(5, 0, 10) // 5 * clamp(15, 10, 0) // 10(两端自动交换) * ``` */ declare function clamp(value: number, min: number, max: number): number; interface MapRangeOptions { /** * 是否把结果钳制到 `outRange` 区间内 * @defaultValue false */ clamp?: boolean; } /** * 把数值从一个区间线性映射到另一个区间 * * 默认对越界输入线性外推,传 `{ clamp: true }` 则把结果限制在 `outRange` 内。 * 两个区间都允许倒序书写(如 `[20, 4]`),钳制同样成立。 * `inRange` 两端相等时比例无从确定,返回 `outRange` 的首端而非除零结果。 * * @category Math * @param value 待映射的数值 * @param inRange 输入区间 `[min, max]` * @param outRange 输出区间 `[min, max]` * @param options 映射行为配置 * @returns 映射后的数值 * @example * ```ts * mapRange(5, [0, 10], [0, 100]) // 50 * mapRange(20, [0, 10], [0, 100]) // 200(默认外推) * mapRange(20, [0, 10], [0, 100], { clamp: true }) // 100 * mapRange(5, [0, 10], [20, 4]) // 12(倒序输出区间) * ``` * @example * ```ts * // 按度数映射节点尺寸,超出统计区间的极值不应撑破视觉上限 * const size = mapRange(degree, [minDegree, maxDegree], [4, 20], { clamp: true }) * ``` */ declare function mapRange(value: number, inRange: readonly [number, number], outRange: readonly [number, number], options?: MapRangeOptions): number; /** * 解析 URL 字符串为结构化对象 * * @category URL * @param url 要解析的 URL 字符串 * @param base 可选的基础 URL,用于解析相对路径 * @returns 解析后的 URL 对象,解析失败返回 null * @example * ```ts * parseUrl('https://example.com:8080/path?query=1#hash') * // { * // href: 'https://example.com:8080/path?query=1#hash', * // protocol: 'https:', * // host: 'example.com:8080', * // hostname: 'example.com', * // port: '8080', * // pathname: '/path', * // search: '?query=1', * // hash: '#hash', * // auth: '', * // origin: 'https://example.com:8080' * // } * * parseUrl('/path', 'https://example.com') * // 解析相对 URL * ``` */ declare function parseUrl(url: string, base?: string): ParsedUrl | null; /** * 检查字符串是否为有效的 URL * * @category URL * @param url 要检查的字符串 * @returns 是否为有效 URL * @example * ```ts * isValidUrl('https://example.com') // true * isValidUrl('not a url') // false * isValidUrl('ftp://files.example.com') // true * ``` */ declare function isValidUrl(url: string): boolean; /** * 检查 URL 是否为绝对路径 * * @category URL * @param url 要检查的 URL * @returns 是否为绝对路径 * @example * ```ts * isAbsoluteUrl('https://example.com') // true * isAbsoluteUrl('/path/to/page') // false * isAbsoluteUrl('//example.com/path') // true (protocol-relative) * ``` */ declare function isAbsoluteUrl(url: string): boolean; /** * 检查 URL 是否为相对路径 * * @category URL * @param url 要检查的 URL * @returns 是否为相对路径 * @example * ```ts * isRelativeUrl('/path/to/page') // true * isRelativeUrl('./page') // true * isRelativeUrl('../page') // true * isRelativeUrl('https://example.com') // false * ``` */ declare function isRelativeUrl(url: string): boolean; /** * 获取 URL 的域名部分 * * @category URL * @param url URL 字符串 * @returns 域名,解析失败返回空字符串 * @example * ```ts * getDomain('https://sub.example.com/path') // 'sub.example.com' * getDomain('https://example.com:8080') // 'example.com' * ``` */ declare function getDomain(url: string): string; /** * 获取 URL 的根域名(顶级域名 + 二级域名) * * @category URL * @param url URL 字符串 * @returns 根域名,解析失败返回空字符串 * @example * ```ts * getRootDomain('https://sub.example.com') // 'example.com' * getRootDomain('https://a.b.example.co.uk') // 'example.co.uk' * ``` */ declare function getRootDomain(url: string): string; /** * 获取 URL 的文件扩展名 * * @category URL * @param url URL 字符串 * @returns 文件扩展名(不含点),无扩展名返回空字符串 * @example * ```ts * getUrlExtension('https://example.com/file.pdf') // 'pdf' * getUrlExtension('https://example.com/file.tar.gz') // 'gz' * getUrlExtension('https://example.com/path/') // '' * ``` */ declare function getUrlExtension(url: string): string; /** * 获取 URL 的文件名 * * @category URL * @param url URL 字符串 * @param includeExtension 是否包含扩展名,默认 true * @returns 文件名 * @example * ```ts * getUrlFilename('https://example.com/path/file.pdf') // 'file.pdf' * getUrlFilename('https://example.com/path/file.pdf', false) // 'file' * getUrlFilename('https://example.com/path/') // '' * ``` */ declare function getUrlFilename(url: string, includeExtension?: boolean): string; /** * 解析 URL 查询字符串为对象 * * @category URL * @param search 查询字符串(可带或不带 ?) * @returns 解析后的查询参数对象 * @example * ```ts * parseQuery('?name=John&age=30') * // { name: 'John', age: '30' } * * parseQuery('tags=a&tags=b&tags=c') * // { tags: ['a', 'b', 'c'] } * * parseQuery('encoded=%E4%B8%AD%E6%96%87') * // { encoded: '中文' } * ``` */ declare function parseQuery(search: string): Record; /** * 将对象序列化为查询字符串 * * @category URL * @param params 查询参数对象 * @param options 序列化选项 * @param options.skipNull 跳过 null 和 undefined 值 * @param options.skipEmpty 跳过空字符串 * @param options.arrayFormat 数组格式: 'repeat' (默认), 'bracket', 'index', 'comma' * @returns 查询字符串(不含 ?) * @example * ```ts * stringifyQuery({ name: 'John', age: 30 }) * // 'name=John&age=30' * * stringifyQuery({ tags: ['a', 'b', 'c'] }) * // 'tags=a&tags=b&tags=c' * * stringifyQuery({ name: '中文' }) * // 'name=%E4%B8%AD%E6%96%87' * * stringifyQuery({ a: null, b: undefined, c: '' }, { skipNull: true, skipEmpty: true }) * // '' * ``` */ declare function stringifyQuery(params: QueryParams, options?: { /** 跳过 null 和 undefined 值 */ skipNull?: boolean; /** 跳过空字符串 */ skipEmpty?: boolean; /** 数组格式: 'repeat' (默认), 'bracket', 'index', 'comma' */ arrayFormat?: 'repeat' | 'bracket' | 'index' | 'comma'; }): string; /** * 从 URL 获取指定查询参数的值 * * @category URL * @param url URL 字符串 * @param key 参数名 * @returns 参数值,不存在返回 null * @example * ```ts * getQueryParam('https://example.com?name=John&age=30', 'name') * // 'John' * * getQueryParam('https://example.com?tags=a&tags=b', 'tags') * // 'a' (返回第一个值) * * getQueryParam('https://example.com', 'name') * // null * ``` */ declare function getQueryParam(url: string, key: string): string | null; /** * 从 URL 获取所有指定查询参数的值(用于多值参数) * * @category URL * @param url URL 字符串 * @param key 参数名 * @returns 参数值数组 * @example * ```ts * getQueryParams('https://example.com?tags=a&tags=b&tags=c', 'tags') * // ['a', 'b', 'c'] * * getQueryParams('https://example.com?name=John', 'name') * // ['John'] * * getQueryParams('https://example.com', 'name') * // [] * ``` */ declare function getQueryParams(url: string, key: string): string[]; /** * 设置 URL 的查询参数 * * @category URL * @param url URL 字符串 * @param key 参数名 * @param value 参数值 * @returns 新的 URL 字符串 * @example * ```ts * setQueryParam('https://example.com', 'page', 1) * // 'https://example.com?page=1' * * setQueryParam('https://example.com?page=1', 'page', 2) * // 'https://example.com?page=2' * * setQueryParam('https://example.com?page=1', 'sort', 'name') * // 'https://example.com?page=1&sort=name' * ``` */ declare function setQueryParam(url: string, key: string, value: QueryParamValue): string; /** * 批量设置 URL 的查询参数 * * @category URL * @param url URL 字符串 * @param params 要设置的参数对象 * @returns 新的 URL 字符串 * @example * ```ts * setQueryParams('https://example.com', { page: 1, limit: 10 }) * // 'https://example.com?page=1&limit=10' * * setQueryParams('https://example.com?page=1', { page: 2, sort: 'name' }) * // 'https://example.com?page=2&sort=name' * ``` */ declare function setQueryParams(url: string, params: QueryParams): string; /** * 追加查询参数(不覆盖已有同名参数) * * @category URL * @param url URL 字符串 * @param key 参数名 * @param value 参数值 * @returns 新的 URL 字符串 * @example * ```ts * appendQueryParam('https://example.com?tag=a', 'tag', 'b') * // 'https://example.com?tag=a&tag=b' * ``` */ declare function appendQueryParam(url: string, key: string, value: QueryParamValue): string; /** * 删除 URL 的指定查询参数 * * @category URL * @param url URL 字符串 * @param key 要删除的参数名 * @returns 新的 URL 字符串 * @example * ```ts * removeQueryParam('https://example.com?page=1&sort=name', 'page') * // 'https://example.com?sort=name' * * removeQueryParam('https://example.com?page=1', 'page') * // 'https://example.com' * ``` */ declare function removeQueryParam(url: string, key: string): string; /** * 检查 URL 是否包含指定查询参数 * * @category URL * @param url URL 字符串 * @param key 参数名 * @returns 是否包含该参数 * @example * ```ts * hasQueryParam('https://example.com?page=1', 'page') // true * hasQueryParam('https://example.com?page=1', 'sort') // false * hasQueryParam('https://example.com?flag', 'flag') // true (无值参数) * ``` */ declare function hasQueryParam(url: string, key: string): boolean; /** * 连接 URL 路径片段 * * @category URL * @param parts URL 片段 * @returns 连接后的 URL * @example * ```ts * joinUrl('https://example.com', 'api', 'users') * // 'https://example.com/api/users' * * joinUrl('https://example.com/', '/api/', '/users/') * // 'https://example.com/api/users/' * * joinUrl('/api', 'users', '123') * // '/api/users/123' * ``` */ declare function joinUrl(...parts: string[]): string; /** * 规范化 URL 路径(移除多余斜杠、处理 . 和 ..) * * @category URL * @param url URL 字符串 * @returns 规范化后的 URL * @example * ```ts * normalizeUrl('https://example.com//api///users/') * // 'https://example.com/api/users/' * * normalizeUrl('https://example.com/api/../users') * // 'https://example.com/users' * * normalizeUrl('/api/./users/../posts') * // '/api/posts' * ``` */ declare function normalizeUrl(url: string): string; /** * 移除 URL 的尾部斜杠 * * @category URL * @param url URL 字符串 * @returns 移除尾部斜杠后的 URL * @example * ```ts * removeTrailingSlash('https://example.com/') // 'https://example.com' * removeTrailingSlash('https://example.com/path/') // 'https://example.com/path' * removeTrailingSlash('https://example.com') // 'https://example.com' * ``` */ declare function removeTrailingSlash(url: string): string; /** * 确保 URL 以斜杠结尾 * * @category URL * @param url URL 字符串 * @returns 带尾部斜杠的 URL * @example * ```ts * ensureTrailingSlash('https://example.com') // 'https://example.com/' * ensureTrailingSlash('https://example.com/path') // 'https://example.com/path/' * ensureTrailingSlash('https://example.com/') // 'https://example.com/' * ``` */ declare function ensureTrailingSlash(url: string): string; /** * 移除 URL 的开头斜杠 * * @category URL * @param url URL 或路径字符串 * @returns 移除开头斜杠后的字符串 * @example * ```ts * removeLeadingSlash('/path/to/page') // 'path/to/page' * removeLeadingSlash('///path') // 'path' * removeLeadingSlash('path') // 'path' * ``` */ declare function removeLeadingSlash(url: string): string; /** * 确保路径以斜杠开头 * * @category URL * @param path 路径字符串 * @returns 带开头斜杠的路径 * @example * ```ts * ensureLeadingSlash('path/to/page') // '/path/to/page' * ensureLeadingSlash('/path') // '/path' * ``` */ declare function ensureLeadingSlash(path: string): string; /** * 构建完整 URL * * @category URL * @param base 基础 URL * @param path 路径部分 * @param query 查询参数 * @param hash 哈希部分 * @returns 完整 URL * @example * ```ts * buildUrl('https://example.com', '/api/users', { page: 1, limit: 10 }) * // 'https://example.com/api/users?page=1&limit=10' * * buildUrl('https://example.com', '/page', null, 'section') * // 'https://example.com/page#section' * * buildUrl('https://example.com', '/api', { ids: [1, 2, 3] }) * // 'https://example.com/api?ids=1&ids=2&ids=3' * ``` */ declare function buildUrl(base: string, path?: string, query?: QueryParams | null, hash?: string): string; /** * 解码 URL 组件(安全版本,失败返回原字符串) * * @category URL * @param str 要解码的字符串 * @returns 解码后的字符串 * @example * ```ts * safeDecodeURIComponent('%E4%B8%AD%E6%96%87') // '中文' * safeDecodeURIComponent('hello%20world') // 'hello world' * safeDecodeURIComponent('%invalid%') // '%invalid%' * ``` */ declare function safeDecodeURIComponent(str: string): string; /** * 编码 URL 组件(安全版本) * * @category URL * @param str 要编码的字符串 * @returns 编码后的字符串 * @example * ```ts * safeEncodeURIComponent('中文') // '%E4%B8%AD%E6%96%87' * safeEncodeURIComponent('hello world') // 'hello%20world' * ``` */ declare function safeEncodeURIComponent(str: string): string; /** * 检查两个 URL 是否同源 * * @category URL * @param url1 第一个 URL * @param url2 第二个 URL * @returns 是否同源 * @example * ```ts * isSameOrigin('https://example.com/a', 'https://example.com/b') // true * isSameOrigin('https://example.com', 'https://sub.example.com') // false * isSameOrigin('https://example.com', 'http://example.com') // false * ``` */ declare function isSameOrigin(url1: string, url2: string): boolean; /** * 将相对 URL 转换为绝对 URL * * @category URL * @param relativeUrl 相对 URL * @param baseUrl 基础 URL * @returns 绝对 URL,转换失败返回原字符串 * @example * ```ts * toAbsoluteUrl('/path', 'https://example.com') * // 'https://example.com/path' * * toAbsoluteUrl('../other', 'https://example.com/api/users') * // 'https://example.com/api/other' * * toAbsoluteUrl('https://other.com', 'https://example.com') * // 'https://other.com' (已是绝对URL,不变) * ``` */ declare function toAbsoluteUrl(relativeUrl: string, baseUrl: string): string; /** * 获取两个 URL 之间的相对路径 * * @category URL * @param from 起始 URL * @param to 目标 URL * @returns 相对路径 * @example * ```ts * getRelativePath('https://example.com/a/b', 'https://example.com/a/c') * // '../c' * * getRelativePath('https://example.com/a', 'https://example.com/a/b/c') * // 'b/c' * ``` */ declare function getRelativePath(from: string, to: string): string; /** * 检查值是否为数组类型 * * @category Validators * @param value 待检查的值 * @returns 是否为数组类型 * @example * ```ts * console.log(isArray([])) // true * console.log(isArray([1, 2, 3])) // true * console.log(isArray({})) // false * console.log(isArray('string')) // false * ``` */ declare function isArray(value: any): value is any[]; /** * 检查值是否为空(null、undefined、空字符串、空数组、空对象) * * @category Validators * @param value 待检查的值 * @returns 是否为空值 * @example * ```ts * console.log(isEmpty(null)) // true * console.log(isEmpty(undefined)) // true * console.log(isEmpty('')) // true * console.log(isEmpty([])) // true * console.log(isEmpty({})) // true * console.log(isEmpty([1, 2])) // false * console.log(isEmpty({ name: 'John' })) // false * console.log(isEmpty('hello')) // false * ``` */ declare function isEmpty(value: any): boolean; /** * 检查值是否为函数类型 * * @category Validators * @param value 待检查的值 * @returns 是否为函数类型 * @example * ```ts * console.log(isFunction(() => {})) // true * console.log(isFunction(function() {})) // true * console.log(isFunction(Math.max)) // true * console.log(isFunction('string')) // false * ``` */ declare function isFunction(value: any): value is (...args: any[]) => any; /** * 检查值是否为有效数字类型 * * @category Validators * @param value 待检查的值 * @returns 是否为有效数字类型 * @example * ```ts * console.log(isNumber(123)) // true * console.log(isNumber(0)) // true * console.log(isNumber(NaN)) // false * console.log(isNumber('123')) // false * ``` */ declare function isNumber(value: any): value is number; /** * 检查值是否为对象类型 * * @category Validators * @param value 待检查的值 * @returns 是否为对象类型 * @example * ```ts * console.log(isObject({})) // true * console.log(isObject({ name: 'John' })) // true * console.log(isObject([])) // false * console.log(isObject(null)) // false * console.log(isObject('string')) // false * ``` */ declare function isObject(value: any): value is AnyObject; /** * 判断值是否为纯对象(不包括数组、函数、日期等) * * @category Validators * @param value 要检查的值 * @returns 是否为纯对象 * @example * ```ts * isPlainObject({}) // true * isPlainObject([]) // false * isPlainObject(new Date()) // false * isPlainObject(() => {}) // false * ``` */ declare function isPlainObject(value: unknown): value is Record; /** * 检查值是否为字符串类型 * * @category Validators * @param value 待检查的值 * @returns 是否为字符串类型 * @example * ```ts * console.log(isString('hello')) // true * console.log(isString('')) // true * console.log(isString(123)) // false * console.log(isString(null)) // false * ``` */ declare function isString(value: any): value is string; /** * 检查值是否为有效的容器类型(对象或数组) * * - isObject: 仅检查纯对象,排除数组 * - isValidContainer: 检查所有可作为容器的类型(对象 + 数组) * * 支持 Vue 3 的 Proxy 对象和 Proxy 数组。 * * @category Validators * @param value - 待检查的值 * @returns 是否为有效容器(对象或数组) * @example * ```ts * isValidContainer({}) // true * isValidContainer([]) // true * isValidContainer(new Proxy({}, {})) // true * isValidContainer(null) // false * isValidContainer('string') // false * isValidContainer(123) // false * ``` */ declare function isValidContainer(value: any): boolean; export { Tree, appendQueryParam, buildUrl, camelCase, capitalize, chunk, clamp, convertSvgToPng, convertToKebabCase, createDeepMerge, createEqualsBy, createRegistry, debounce, deepClone, deepMerge, ensureLeadingSlash, ensureTrailingSlash, equalsBy, extractFilename, flatten, formatFileSize, getDomain, getPath, getQueryParam, getQueryParams, getRandomUUID, getRelativePath, getRootDomain, getUrlExtension, getUrlFilename, hasQueryParam, isAbsoluteUrl, isArray, isEmpty, isFunction, isNumber, isObject, isPlainObject, isRelativeUrl, isSameOrigin, isString, isValidContainer, isValidUrl, joinPath, joinUrl, kebabCase, lengthToPx, lowerCase, lowerFirst, mapRange, normalizeUrl, omit, omitUndefined, parseQuery, parseUrl, pascalCase, pick, pipe, removeLeadingSlash, removeQueryParam, removeTrailingSlash, replaceCurrentColor, safeDecodeURIComponent, safeEncodeURIComponent, separate, separateMany, setPath, setQueryParam, setQueryParams, simpleHash, sleep, sleepWithCancel, snakeCase, splitHighlight, startCase, stringifyMinimark, stringifyQuery, throttle, toAbsoluteUrl, toPath, triggerDownload, unique, upperCase, upperFirst, useAppStorage, useCopyCode, useInfiniteScrollBinding, useOverflowDetection, words }; export type { AnyObject, ApiAwaitable, ApiAwaitedReturn, ApiUnwrapPromise, AppStorageReturn, ArrayFieldKeys, ArrayMergeStrategy, ComponentAttrs, ComponentEmit, ComponentExposed, ComponentProps, ComponentSlots, ComponentType, CustomMerger, DeepMerge, DeepMergeOptions, DeepPartial, FirstParam, FirstParameter, GetFieldValue, GetObjectField, HighlightSegment, IsAny, IsComponent, IsPlainObject, KnownKeys, MapRangeOptions, MaybeFn, Merge, MinimarkDocument, MinimarkNode, MutableByKeys, NestedKeys, NonObjectFieldKeys, NullHandlingStrategy, ObjectFieldKeys, OmitByKey, ParsedUrl, PartialByKeys, PathInput, PathSegment, PathSegments, PickByKey, Prettify, QueryParamValue, QueryParams, ReactiveValue, ReadonlyByKeys, Registry, RegistryOptions, RenameKeys, RequiredByKeys, StorageConfig, StorageConfigInput, StorageType, StringOrVNode, StripNullable, Suggest, TreeConfig, TreeConfigInput, TreeNode, TreePredicate, TreeStats, TreeTransformer, TreeVisitor, UnionToIntersection, UnknownObject, UseInfiniteScrollBindingOptions, UseOverflowDetectionOptions, UseOverflowDetectionReturn, VoidCallback, WidenLiteral };