Orika-JS 是一个专为 TypeScript 设计的对象映射库,用于在分层架构中优雅地处理 Entity、DTO、VO 之间的转换。
- 类型安全 - 完整的 TypeScript 类型推导和编译时检查
- 约定优于配置 - 同名字段自动映射,零配置即可使用
- 高性能 - 智能缓存、批量处理、惰性求值
- 异步支持 - 原生 Promise,支持异步字段转换
- 框架集成 - 深度集成 React、Vue 3、Zustand、Jotai、Pinia
- 轻量级 - 零运行时依赖,核心库仅 8KB gzipped
- API 层:后端 DTO 与前端 Model 转换
- 业务层:Entity 与 DTO 之间的双向映射
- 视图层:Model 转换为 ViewModel
- 数据持久化:领域对象与数据库实体转换
pnpm add @orika-js/core框架集成包(可选):
pnpm add @orika-js/react # React
pnpm add @orika-js/vue3 # Vue 3
pnpm add @orika-js/pinia # Pinia
pnpm add @orika-js/zustand # Zustand
pnpm add @orika-js/jotai # Jotaiimport { createMapperBuilder, MapperFactory } from '@orika-js/core';
// 定义数据模型
class User {
id: number;
username: string;
password: string;
email: string;
}
class UserDTO {
id: number;
displayName: string;
email: string;
}
// 配置映射规则
createMapperBuilder<User, UserDTO>()
.from(User)
.to(UserDTO)
.mapField('username', 'displayName') // 字段重命名
.exclude('password') // 排除敏感字段
.register();
// 执行映射
const factory = MapperFactory.getInstance();
// 单个对象
const dto = factory.map(user, User, UserDTO);
// 批量映射
const dtos = factory.mapArray(users, User, UserDTO);适用于需要从其他数据源获取关联数据的场景。
createMapperBuilder<Post, PostDetailDTO>()
.from(Post)
.to(PostDetailDTO)
.forMemberAsync('author', async (src) => {
const user = await userService.getById(src.authorId);
return factory.map(user, User, UserDTO);
})
.forMemberAsync('comments', async (src) => {
return await commentService.getByPostId(src.id);
})
.register();
// 自动处理所有异步操作
const detail = await factory.mapAsync(post, Post, PostDetailDTO);支持计算字段、条件映射等复杂场景。
createMapperBuilder<Product, ProductDTO>()
.from(Product)
.to(ProductDTO)
// 计算字段
.forMember('totalPrice', (src) => src.price * src.quantity)
// 条件映射
.mapFieldWhen('discountPrice', 'finalPrice',
(src) => src.onSale,
(src) => src.price * (1 - src.discount)
)
// 类型转换
.forMember('createdAt', (src) => new Date(src.createTime))
.register();处理复杂的对象结构。
createMapperBuilder<Order, OrderDTO>()
.from(Order)
.to(OrderDTO)
.forMember('customer', (src) =>
factory.map(src.user, User, UserDTO)
)
.forMember('items', (src) =>
factory.mapArray(src.orderItems, OrderItem, OrderItemDTO)
)
.register();将后端 API 返回的数据转换为前端使用的模型。
// 后端返回的数据结构
interface APIResponse {
user_id: number;
user_name: string;
created_at: string;
}
// 前端数据模型
class UserModel {
id: number;
name: string;
createdAt: Date;
}
// 配置映射
createMapperBuilder<APIResponse, UserModel>()
.from(Object as any)
.to(UserModel)
.mapField('user_id', 'id')
.mapField('user_name', 'name')
.forMember('createdAt', (src) => new Date(src.created_at))
.register();
// 使用
const response = await api.getUser();
const user = factory.map(response, Object as any, UserModel);将表单数据转换为 API 请求格式。
createMapperBuilder<FormData, CreateUserRequest>()
.from(FormData)
.to(CreateUserRequest)
.forMember('age', (src) => parseInt(src.age))
.forMember('tags', (src) => src.tagString.split(','))
.validate((src, dest) => {
if (!dest.email.includes('@')) {
throw new Error('Invalid email format');
}
})
.register();为列表视图准备优化的数据结构。
createMapperBuilder<Product, ProductListItemDTO>()
.from(Product)
.to(ProductListItemDTO)
.forMember('displayPrice', (src) =>
src.onSale ? src.salePrice : src.originalPrice
)
.forMember('stockStatus', (src) => {
if (src.stock === 0) return 'sold-out';
if (src.stock < 10) return 'low-stock';
return 'in-stock';
})
.register();import { useMapper, useMemoizedMapper } from '@orika-js/react';
function UserProfile({ user }) {
// 自动响应依赖变化
const dto = useMemoizedMapper(user, User, UserDTO);
return <div>{dto.displayName}</div>;
}完整文档:React 集成指南
import { useMapper, mapToReactive } from '@orika-js/vue3';
export default {
setup() {
const { map } = useMapper(User, UserDTO);
// 响应式映射
const userDTO = mapToReactive(user, User, UserDTO);
return { userDTO };
}
}完整文档:Vue 3 集成指南
// Pinia
import { createPiniaMapperPlugin } from '@orika-js/pinia';
pinia.use(createPiniaMapperPlugin());
// Zustand
import { createMappedStore } from '@orika-js/zustand';
const useStore = createMappedStore(/* ... */);
// Jotai
import { atomWithMapper } from '@orika-js/jotai';
const userDTOAtom = atomWithMapper(userAtom, User, UserDTO);| 包 | 版本 | 大小 | 描述 |
|---|---|---|---|
| @orika-js/core | 8KB | 核心映射引擎 | |
| @orika-js/react | 3KB | React 集成 | |
| @orika-js/vue3 | 3KB | Vue 3 集成 | |
| @orika-js/pinia | 2KB | Pinia 插件 | |
| @orika-js/zustand | 2KB | Zustand 中间件 | |
| @orika-js/jotai | 2KB | Jotai 集成 |
# 安装依赖
pnpm install
# 构建所有包
pnpm build
# 开发模式
pnpm dev
# 运行示例
pnpm --filter react-demo dev欢迎贡献代码、报告问题或提出建议!请查看贡献指南了解详情。
灵感来自 Orika (Java) 和 AutoMapper (.NET)