npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

iota-utools

v0.1.5

Published

一个功能丰富、类型安全的 JavaScript/TypeScript 工具库,专为现代 Web 开发而设计。我精心打造了这套工具集,旨在提供高效、可靠且易用的解决方案。

Downloads

206

Readme

IOTA Utils

一个功能丰富、类型安全的 JavaScript/TypeScript 工具库,专为现代 Web 开发而设计。我精心打造了这套工具集,旨在提供高效、可靠且易用的解决方案。

核心特性

  • 🚀 高性能:优化的算法和数据结构
  • 🔒 类型安全:完整的 TypeScript 支持
  • 📦 模块化:按需导入,减少打包体积
  • 🧪 测试覆盖:全面的单元测试
  • 📚 文档完善:详细的使用说明和示例

安装

npm install iota-utils
# 或
yarn add iota-utils
# 或
pnpm add iota-utils

快速开始

import { getTypeof, setLocalStorage, catchError } from "iota-utils";

// 类型判断
console.log(getTypeof([])); // 'array'

// 存储操作
setLocalStorage("user", { name: "John" });

// 错误处理
const [err, data] = await catchError(async () => {
  return await fetch("/api/data").then((r) => r.json());
});

功能模块详解

🔍 类型判断 (Type Utilities)

强大的类型检测和判断工具,支持所有 JavaScript 数据类型。

import {
  getTypeof,
  isArray,
  isBoolean,
  isString,
  isNumber,
  isObject,
  isFunction,
  isMap,
  isSet,
  isSymbol,
} from "iota-utils";

// 获取精确类型名称
getTypeof([]); // 'array'
getTypeof({}); // 'object'
getTypeof(""); // 'string'
getTypeof(42); // 'number'
getTypeof(true); // 'boolean'
getTypeof(() => {}); // 'function'
getTypeof(null); // 'null'
getTypeof(undefined); // 'undefined'

// 类型守卫函数
if (isArray(value)) {
  value.forEach((item) => console.log(item));
}

if (isObject(data)) {
  Object.keys(data).forEach((key) => {
    console.log(`${key}: ${data[key]}`);
  });
}

最佳实践

  • 在运行时类型检查时使用 is* 函数
  • getTypeof 适合调试和日志记录
  • 结合 TypeScript 的类型守卫使用

💾 存储操作 (Storage)

完整的浏览器存储解决方案,支持监听和批量操作。

基础存储操作

import {
  setLocalStorage,
  getLocalStorage,
  removeLocalStorageKey,
  setSessionStorage,
  getSessionStorage,
  removeSessionStorageKey,
} from "iota-utils";

// LocalStorage 操作
setLocalStorage("user", { id: 1, name: "John", email: "[email protected]" });
const user = getLocalStorage("user"); // 自动反序列化
removeLocalStorageKey("user");

// SessionStorage 操作
setSessionStorage("tempToken", "abc123");
const token = getSessionStorage("tempToken");
removeSessionStorageKey("tempToken");

// 批量删除
removeLocalStorageKey("key1", "key2", "key3");

存储监听

import { monitorStorage } from "iota-utils";

interface StorageEvent {
  key: string;
  newValue: any;
  oldValue: any;
  storageArea: "localStorage" | "sessionStorage";
}

// 开始监听
const cleanup = monitorStorage({
  type: "both", // 'local' | 'session' | 'both'
  emitUnchanged: false, // 值未变化时是否触发
  onError: (error) => console.error("Storage monitoring error:", error),
});

// 监听事件
window.addEventListener("local", (e: CustomEvent<StorageEvent>) => {
  console.log("Local storage changed:", e.detail);
});

window.addEventListener("session", (e: CustomEvent<StorageEvent>) => {
  console.log("Session storage changed:", e.detail);
});

// 停止监听
cleanup();

注意事项

  • 存储的数据会自动 JSON 序列化/反序列化
  • 监听器会自动处理跨标签页同步
  • 错误处理确保存储操作的稳定性

📁 文件操作 (File Operations)

文件下载和上传的便捷解决方案。

import { downFile, downStream } from "iota-utils";

// 下载文本文件
downFile("Hello, World!", "greeting.txt", "text/plain;charset=utf-8");

// 下载二进制数据
const blob = new Blob(["binary data"], { type: "application/octet-stream" });
downFile(blob, "data.bin");

// 下载远程文件流
await downStream(
  "https://api.example.com/files/document.pdf",
  "document.pdf",
  "Bearer your-token-here",
  { userId: 123, format: "pdf" },
);

📊 数组处理 (Array Utilities)

高效的数组操作和转换工具。

import { uniqueArrayByProperty, arraySlice } from "iota-utils";

// 对象数组去重
const users = [
  { id: 1, name: "John", department: "IT" },
  { id: 2, name: "Jane", department: "HR" },
  { id: 1, name: "John", department: "IT" }, // 重复
  { id: 3, name: "Bob", department: "Finance" },
];

const uniqueUsers = uniqueArrayByProperty(users, "id");
// 结果: 移除了重复的 id: 1

// 数组分片
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const chunks = arraySlice(numbers, 3);
// 结果: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

🏗️ 对象处理 (Object Utilities)

对象扁平化和还原的强大工具。

import { flattenObject, restoreObject } from "iota-utils";

// 深度扁平化
const nested = {
  user: {
    profile: {
      name: "John",
      age: 30,
      address: {
        street: "123 Main St",
        city: "Anytown",
        coordinates: {
          lat: 40.7128,
          lng: -74.006,
        },
      },
    },
    preferences: {
      theme: "dark",
      notifications: true,
    },
  },
  metadata: {
    version: "1.0",
    timestamp: Date.now(),
  },
};

const flat = flattenObject(nested);
// 结果:
// {
//   'user.profile.name': 'John',
//   'user.profile.age': 30,
//   'user.profile.address.street': '123 Main St',
//   'user.profile.address.city': 'Anytown',
//   'user.profile.address.coordinates.lat': 40.7128,
//   'user.profile.address.coordinates.lng': -74.0060,
//   'user.preferences.theme': 'dark',
//   'user.preferences.notifications': true,
//   'metadata.version': '1.0',
//   'metadata.timestamp': 1640995200000
// }

// 还原对象结构
const restored = restoreObject(flat);
// 结果与原始 nested 对象完全相同

🧵 字符串处理 (String Utilities)

字符串格式化和模板处理的实用工具。

import { format, parmas } from "iota-utils";

// 字符串格式化(类似 C# String.Format)
const greeting = format("Hello, {0}! Welcome to {1}.", "John", "our app");
// 结果: 'Hello, John! Welcome to our app.'

const message = format(
  "User {0} scored {1} points in {2}.",
  "Alice",
  95,
  "Math",
);
// 结果: 'User Alice scored 95 points in Math.'

// 查询字符串处理
const queryString = "name=John+Doe&age=30&city=New+York&active=true";
const params = parmas(queryString);
// 结果: { name: 'John Doe', age: '30', city: 'New York', active: 'true' }

// 对象转查询字符串
const obj = { name: "John Doe", age: 30, city: "New York" };
const query = parmas(obj); // 注意:这里可能需要 encodeParams 函数,文档中是 parmas
// 假设有 encodeParams: 'name=John+Doe&age=30&city=New+York'

🌳 树形结构处理 (Tree Utilities)

完整的树形数据结构操作工具集。

import {
  toFlatTree,
  toTreeFlat,
  deepClone,
  deleteTreeNode,
  findTreeNode,
  fuzzySearchTree,
  TreeNode,
} from "iota-utils";

// 定义树节点接口
interface MyTreeNode {
  id: number;
  title: string;
  children?: MyTreeNode[];
  expanded?: boolean;
}

// 示例树结构
const tree: MyTreeNode = {
  id: 1,
  title: "Root",
  children: [
    {
      id: 2,
      title: "Branch A",
      children: [
        { id: 4, title: "Leaf 1" },
        { id: 5, title: "Leaf 2" },
      ],
    },
    {
      id: 3,
      title: "Branch B",
      children: [{ id: 6, title: "Leaf 3" }],
    },
  ],
};

// 树转扁平结构
const flat = toFlatTree(tree);
// 结果: 包含所有节点及其层级信息的数组

// 扁平结构转树
const restoredTree = toTreeFlat(flat);

// 深拷贝(完整克隆树结构)
const clonedTree = deepClone(tree);

// 删除节点及其子节点
const newTree = deleteTreeNode(tree, 2); // 删除 id 为 2 的节点

// 查找节点
const foundNode = findTreeNode(tree, 5, "id");
// 返回 id 为 5 的节点

// 模糊搜索
const searchResults = fuzzySearchTree(tree, "Leaf", "title");
// 返回所有 title 包含 'Leaf' 的节点

⚡ 异步处理 (Async Utilities)

Go 风格的错误处理,让异步代码更清晰。

import { catchError, wrapCatch } from "iota-utils";

// 直接错误捕获
async function fetchUserData(userId: number) {
  const [err, data] = await catchError(async () => {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return await response.json();
  });

  if (err) {
    console.error("Failed to fetch user:", err);
    return null;
  }

  return data;
}

// 包装函数使用
const safeFetchUser = wrapCatch(async (userId: number) => {
  const response = await fetch(`/api/users/${userId}`);
  return await response.json();
});

// 使用包装后的函数
const [err, user] = await safeFetchUser(123);
if (err) {
  console.error("Error:", err);
} else {
  console.log("User:", user);
}

// 同步函数也可以包装
const safeParseJson = wrapCatch((jsonString: string) => {
  return JSON.parse(jsonString);
});

const [parseErr, parsedData] = safeParseJson('{"name": "John"}');

⬆️ 文件上传 (Upload Utilities)

大文件切片上传,支持进度回调和断点续传。

import { uploadSlice } from "iota-utils";

async function uploadLargeFile(file: File) {
  const CHUNK_SIZE = 1024 * 1024; // 1MB
  const UPLOAD_URL = "https://api.example.com/upload";

  try {
    const result = await uploadSlice(
      file,
      CHUNK_SIZE,
      UPLOAD_URL,
      (progress: number) => {
        console.log(`Upload progress: ${progress}%`);
      },
      {
        headers: {
          Authorization: "Bearer token123",
          "X-File-Name": file.name,
        },
        // 其他配置...
      },
    );

    if (result.finish) {
      console.log("Upload completed successfully!");
    } else {
      console.log("Some chunks failed:", result.failedSlices);
      // 可以在这里实现重试逻辑
    }
  } catch (error) {
    console.error("Upload failed:", error);
  }
}

🆔 UUID 生成 (UUID Utilities)

灵活的唯一标识符生成工具。

import { generateUUID, generateString } from "iota-utils";

// 生成标准 UUID v4
const uuid = generateUUID();
// 示例: "550e8400-e29b-41d4-a716-446655440000"

// 使用自定义模板
const customId = generateUUID("xxxx-yyyy-zzzz");
// 示例: "a1b2-c3d4-e5f6"

// 生成随机字符串(字母开头)
const randomStr = generateString(); // 默认 8 位
// 示例: "Ak7x9Pq2"

const longStr = generateString(16);
// 示例: "Bw3mK9nX5vY2pQ8r"

// 生成指定长度的随机字符串
const shortId = generateString(4);
// 示例: "X9k2"

📅 日期处理 (Date Utilities)

日历生成和日期操作工具。

import { generateCalendar } from "iota-utils";

interface CalendarDay {
  date: Date;
  meta: {
    year: number;
    month: number; // 1-12
    day: number; // 1-31
    dayOfWeek: string;
    type: "prev" | "current" | "next";
    formattedDate: string;
  };
}

// 生成指定年月的完整日历数据
const calendar: CalendarDay[] = generateCalendar(2024, 3); // 2024年3月

// 日历数据包含:
// - 上个月的尾部日期(用于填充日历网格)
// - 当月的完整日期
// - 下个月的开头日期(用于填充日历网格)

// 使用示例:渲染日历组件
calendar.forEach((day) => {
  const { date, meta } = day;
  if (meta.type === "current") {
    console.log(`${meta.formattedDate}: ${meta.dayOfWeek}`);
  }
});

🛠️ 通用工具 (General Utilities)

防抖、节流、复制文本、延时等常用工具函数。

import { debounce, throttle, copyText, sleep } from "iota-utils";

// 防抖函数
const debouncedSearch = debounce((query: string) => {
  console.log("Searching for:", query);
  // 执行搜索逻辑...
}, 300);

// 使用防抖搜索
debouncedSearch("hello");
debouncedSearch("hello world"); // 只有最后一次调用会执行

// 节流函数
const throttledScroll = throttle(() => {
  console.log("Scroll event");
}, 100);

// 窗口滚动事件
window.addEventListener("scroll", throttledScroll);

// 复制文本到剪贴板
await copyText("Hello, World!");

// 延时执行
await sleep(1000); // 暂停 1 秒
console.log("1 second later...");

// 组合使用:带防抖的异步操作
const debouncedAsyncSave = debounce(async (data: any) => {
  const [err] = await catchError(async () => {
    await saveToServer(data);
  });
  if (err) {
    console.error("Save failed:", err);
  }
}, 500);

类型定义

// 错误结果类型
export type ErrorResult<T> = [Error | null, T | undefined];

// 树节点接口
export interface TreeNode {
  id: string | number;
  children?: TreeNode[];
  [key: string]: any;
}

// 存储监听配置
export interface MonitorStorageOptions {
  type: "local" | "session" | "both";
  emitUnchanged?: boolean;
  onError?: (error: Error) => void;
}

// 文件上传配置
export interface UploadConfig {
  headers?: Record<string, string>;
  timeout?: number;
  retries?: number;
  [key: string]: any;
}

最佳实践

1. 错误处理

// ✅ 推荐:使用 catchError 进行统一错误处理
const [err, data] = await catchError(async () => {
  return await apiCall();
});
if (err) {
  handleError(err);
  return;
}
processData(data);

// ❌ 避免:传统的 try-catch
try {
  const data = await apiCall();
  processData(data);
} catch (err) {
  handleError(err);
}

2. 类型安全

// ✅ 利用 TypeScript 类型推断
const [err, user] = await catchError(fetchUser);
if (err) return;
// user 的类型被正确推断,无需额外类型断言

3. 性能优化

// ✅ 合理使用防抖和节流
const debouncedSearch = debounce(searchAPI, 300);
const throttledResize = throttle(handleResize, 100);

// ✅ 批量存储操作
setLocalStorage("batchData", largeObject);

4. 内存管理

// ✅ 及时清理监听器
const cleanup = monitorStorage({ type: "both" });
// ... 使用中 ...
cleanup(); // 清理以防止内存泄漏

浏览器兼容性

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+

许可证

MIT License - 详见 LICENSE 文件

发布与版本管理

项目自带一个辅助脚本 npm run release(执行 node scripts/publish.js),用于自动:

  1. 询问或自动计算下一个语义版本号
  2. 运行生产构建
  3. 提交 package.json 修改并打 Git 标签
  4. 推送代码和标签到远程仓库
  5. 发布到 npm

脚本会在开始前检查工作区是否干净,失败时会回滚版本号。它还会自动检测已有的 Git 标签,如果用户输入的版本已经被使用,会自动递增直到找到可用的版本号并给出提示。

⚠️ 如果你手动创建了标签(例如 v0.1.6),再运行 npm run release 时脚本会跳过已有版本并继续到下一个可用版本,避免冲突。

需要手动删除旧标签时可以执行:

# 删除本地标签
git tag -d v0.1.6
# 同步删除远程标签
git push --delete origin v0.1.6

贡献

欢迎提交 Issue 和 Pull Request!在贡献代码前,请确保:

  1. 所有测试通过:npm test
  2. 代码格式化:npm run lint
  3. 类型检查:npm run type-check