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 🙏

© 2025 – Pkg Stats / Ryan Hefner

venom-vo

v1.1.1

Published

一个基于 TypeScript 装饰器和反射机制的VO数据处理类库

Readme

Venom 数据处理系统

一个基于 TypeScript 装饰器和反射机制的数据处理类库,类似于 NestJS 的依赖注入系统,支持 JSON 数据填充、类型转换和字段标签化。

特性

  • 🚀 基于 TypeScript 装饰器的字段定义
  • 📝 自动类型推断和元数据收集
  • 🏷️ 字段标签化(label 方法)
  • 🎯 枚举支持和自定义格式化
  • 📦 预设配置支持

安装依赖

pnpm add reflect-metadata
pnpm add -D @types/node
pnpm add -D jest ts-jest @types/jest

使用 npm 可替换为 npm install reflect-metadatanpm install --save-dev jest ts-jest @types/jest

运行测试

pnpm test

或使用 npm:

npm test

核心功能

1. 实例创建

推荐使用静态 create 方法

const user = User.create(data); // 推荐方式

分步骤创建

const user = new User();
user.fromJson(data);

基本用法

1. 定义数据类

import { Venom, field } from 'venom-vo';
import { Enum } from 'enum-plus';

const Gender = Enum({
  MALE: {
    label: '男',
    value: 1,
  },
  FEMALE: {
    label: '女',
    value: 2,
  },
});

class BaseUser extends Venom {
  @field()
  name?: string;

  @field({ enum: Gender })
  gender?: number;

  @field('date') // 使用预设配置
  birthDate?: string;

  @field({
    from: (v) => `$${v.toFixed(2)}`,
  })
  salary?: number;
}

class User extends BaseUser {
  @field({
    type: BaseUser,
  })
  children?: BaseUser[];
}

2. 使用数据类

// 推荐使用静态 create 方法创建实例
const user = User.create({
  name: 'Alice',
  gender: 1,
  birthDate: '1990-01-01',
  salary: 5000,
  children: [{ name: 'Bob', gender: 1, birthDate: '2010-01-01' }],
});

// 或者分步骤创建
const user2 = new User();
user2.fromJson(apiResponseData);

// 获取字段值(原始值)
console.log(user.name); // "Alice"
console.log(user.gender); // 1 (原始值)
console.log(user.getLabel('gender')); // "男" (转换后的标签)

field 装饰器选项

基本选项

interface FieldOptions {
  enum?: any; // 枚举对象
  toView?: (value: any) => any; // 转换为视图显示时的转换函数
  toForm?: (value: any) => any; // 转换为表单数据时的转换函数
  type?: any; // 手动指定类型,用于数组元素类型
}

枚举支持

import { Enum } from 'enum-plus';
import { Venom, field } from './index';

// 定义性别枚举
const Gender = Enum({
  男: 1,
  女: 2,
});

class User extends Venom {
  @field({ enum: Gender })
  gender?: number;
}

const user = new User({ gender: 1 });
console.log(user.gender); // "男"

自定义转换

class User extends Venom {
  @field({
    toForm: (v) => new Date(v), // JSON 字符串转 Date 对象
  })
  createdAt?: string;
}

预设配置

支持以下预设配置字符串:

  • 'date' - 日期格式化为 YYYY-MM-DD
  • 'datetime' - 日期时间格式化为 YYYY-MM-DD HH:mm:ss
  • 'time' - 时间格式化为 HH:mm:ss
  • 'price' - 价格处理(分转元,保留两位小数)
  • 'currency' - 货币格式化(分转元,带 ¥ 符号)
  • 'string' - 字符串处理
  • 'number' - 数字处理
  • 'boolean' - 布尔值处理
class Product extends Venom {
  @field('date')
  createDate?: string; // "2024-01-15"

  @field('datetime')
  updateTime?: string; // "2024-01-15 10:30:00"

  @field('time')
  openTime?: string; // "09:30:00"

  @field('price')
  price?: number; // "99.99" (分转元)

  @field('currency')
  originalPrice?: number; // "¥199.99" (带货币符号)
}

Venom 类方法

fromJson(data: any)

从 JSON 数据填充实例字段

getLabel(fieldName: string): any

获取字段的转换后标签(经过枚举转换或 toView 函数处理的值)。

const user = User.create({
  name: 'Alice',
  gender: 1,
  age: 18,
});

// 字段直接存储原始值
console.log(user.gender); // 1
console.log(user.age); // 18

// 获取转换后的标签
console.log(user.getLabel('gender')); // '男'
console.log(user.getLabel('age')); // 19 (经过toView函数转换)

toView(): any

输出实例经过配置转换的 JSON 对象,支持嵌套对象和数组。

class SubUser extends Venom {
  @field()
  title?: string;

  @field({
    toView: (v) => v.toUpperCase(),
  })
  description?: string;
}

class User extends Venom {
  @field()
  name?: string;

  @field({ enum: Gender })
  gender?: number;

  @field({
    toView: (v) => v + 1,
  })
  age?: number;

  @field({ type: SubUser })
  profile?: SubUser;

  @field({ type: SubUser })
  children?: SubUser[];
}

const user = User.create({
  name: 'Alice',
  gender: 1,
  age: 18,
  profile: {
    title: 'Profile Title',
    description: 'hello world',
  },
  children: [{ title: 'Child 1', description: 'first child' }],
});

// 输出转换后的JSON对象
console.log(user.toView());
// {
//   "name": "Alice",
//   "gender": "男",
//   "age": 19,
//   "profile": {
//     "title": "Profile Title",
//     "description": "HELLO WORLD"
//   },
//   "children": [
//     {
//       "title": "Child 1",
//       "description": "FIRST CHILD"
//     }
//   ]
// }

toForm(): any

输出适合表单使用的 JSON 对象,支持自定义转换:

class User extends Venom {
  @field({
    toForm: (v) => String(v), // 表单中转为字符串
  })
  age?: number;

  @field({
    toForm: (v) => v.toLowerCase(), // 表单中转为小写
  })
  description?: string;

  @field({ type: SubUser })
  profile?: SubUser;

  @field({ type: SubUser })
  children?: SubUser[];
}

const user = User.create({
  age: 18,
  description: 'HELLO WORLD',
  profile: {
    title: 'Profile Title',
    description: 'hello world',
  },
  children: [{ title: 'Child 1', description: 'first child' }],
});

// 输出适合表单的JSON对象
console.log(user.toForm());
// {
//   "age": "18",           // 经过 toForm 转换为字符串
//   "description": "hello world", // 转为小写
//   "profile": {...},      // 嵌套对象也会调用 toForm
//   "children": [...]      // 数组中的嵌套对象也会转换
// }

static getFields(): FieldMetadata[]

获取类的字段元数据

字段值和标签

字段存储原始值,使用 getLabel 方法获取转换后的标签:

const user = User.create({ name: 'Alice', gender: 1 });

// 获取字段值(原始值)
console.log(user.name); // "Alice"
console.log(user.gender); // 1 (原始值)

// 获取转换后的标签
console.log(user.getLabel('gender')); // "男" (枚举转换后的标签)

嵌套对象支持

class Address extends Venom {
  @field()
  street?: string;

  @field()
  city?: string;
}

class User extends Venom {
  @field()
  name?: string;

  @field()
  address: Address = new Address();

  @field({
    type: Address,
  })
  addresses: Address[];
}

const user = new User({
  name: 'Alice',
  address: { street: '123 Main St', city: 'New York' },
  addresses: [{ street: '456 Oak Ave', city: 'Boston' }],
});

注意事项

  1. 需要在 tsconfig.json 中启用装饰器支持:

    {
      "compilerOptions": {
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
      }
    }
  2. 必须导入 reflect-metadata

  3. 字段类型需要明确定义,以便正确获取元数据