
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
custom-automapper
Advanced tools
A powerful, type-safe object mapping library for TypeScript and NestJS
A powerful, type-safe, extensible object mapping library for TypeScript and NestJS, built for real-world production use.
It supports decorators, caching, async mapping, validation, and more — all without the @automapper/core dependency.
mapFrom, ignore, transform, etc.)npm install @custom-automapper
# or
yarn add @custom-automapper
import { Mapper, AutoMap } from '@custom-automapper';
// DTOs
class SourceDTO {
@AutoMap()
name: string;
@AutoMap()
age: number;
}
class TargetDTO {
@AutoMap()
name: string;
@AutoMap()
age: number;
}
// Mapper
const mapper = new Mapper();
mapper.createMap(SourceDTO, TargetDTO);
const source = new SourceDTO();
source.name = 'John';
source.age = 30;
const target = mapper.map(source, TargetDTO);
console.log(target); // { name: 'John', age: 30 }
You can configure global options like caching, cloning, or naming conventions in the constructor:
import { Mapper } from '@custom-automapper';
const mapper = new Mapper({
globalOptions: {
deepClone: true,
skipUndefined: true,
},
cache: {
enabled: true, // Enable caching globally
strategy: 'memory', // 'memory' (default) or custom
}
});
mapper.setCacheEnabled(true);
console.log(mapper.isGlobalCacheEnabled()); // true
mapper.setCacheEnabled(false);
You can explicitly define property mappings using mapFrom:
mapper.createMap(SourceDTO, TargetDTO, {
name: mapper.mapFrom(src => src.name.toUpperCase()), // transform source value
age: mapper.mapFrom('age') // map directly by key
});
Generate reverse mapping automatically:
mapper.createMap(SourceDTO, TargetDTO, {
name: src => src.name,
age: src => src.age,
});
// Create reverse mapping (TargetDTO → SourceDTO)
mapper.createReverseMap(SourceDTO, TargetDTO);
When mapping data that involves async transforms (e.g., fetching data or calling async functions):
await mapper.createMap(UserEntity, UserDTO, {
profileUrl: async src => await getProfileUrl(src.id)
});
const result = await mapper.mapAsync(userEntity, UserDTO);
const users = [user1, user2, user3];
const dtos = mapper.mapArray(users, UserDTO);
// Or async version
const dtosAsync = await mapper.mapArrayAsync(users, UserDTO);
Apply conditional mapping logic dynamically:
const target = mapper.mapConditional(source, TargetDTO, [
{
condition: src => src.age > 18,
map: src => ({ status: 'Adult' })
},
{
condition: src => src.age <= 18,
map: src => ({ status: 'Minor' })
}
]);
Attach validation rules per class property and validate mapped objects.
mapper.addValidation(UserDTO, 'email', {
validate: value => value.includes('@'),
message: 'Email must contain @ symbol'
});
await mapper.validate(new UserDTO()); // throws if invalid
Decorators like @AutoMap, @MapFrom, and @MapTo automatically handle property mapping.
class AddressDTO {
@AutoMap()
city: string;
}
class UserDTO {
@AutoMap()
name: string;
@AutoMap(() => AddressDTO)
address: AddressDTO;
}
Get detailed insights into which properties were mapped or skipped.
const result = mapper.mapWithMetadata(source, TargetDTO);
console.log(result.metadata);
/*
{
mappedProperties: ['name', 'age'],
skippedProperties: [],
errors: [],
executionTime: 2
}
*/
Each mapped source object is cached by reference using a WeakMap, minimizing re-computation on repeated mapping calls.
mapper.setCacheEnabled(true);
const src = new SourceDTO();
src.name = 'Cached User';
src.age = 25;
const first = mapper.map(src, TargetDTO);
const second = mapper.map(src, TargetDTO); // served from cache
| Method | Description |
|---|---|
map() | Maps an object synchronously |
mapAsync() | Maps asynchronously |
mapArray() | Maps an array synchronously |
mapArrayAsync() | Maps an array asynchronously |
createReverseMap() | Generates reverse mapping |
clear() | Clears registry and cache |
getMappings() | Lists registered mappings |
mapWithMetadata() | Maps with runtime metadata |
class UserEntity {
@AutoMap()
id: number;
@AutoMap()
fullName: string;
@AutoMap()
email: string;
}
class UserDTO {
@AutoMap()
id: number;
@AutoMap()
name: string;
@AutoMap()
email: string;
}
const mapper = new Mapper({ cache: { enabled: true } });
mapper.createMap(UserEntity, UserDTO, {
name: src => src.fullName
});
const entity = { id: 1, fullName: 'Nishit Shiv', email: 'nishit@example.com' };
const dto = mapper.map(entity, UserDTO);
console.log(dto); // { id: 1, name: 'Nishit Shiv', email: 'nishit@example.com' }
@automapper/core| Feature | Custom AutoMapper | @automapper/core |
|---|---|---|
| Decorator-driven mapping | ✅ | ✅ |
| Nested object mapping | ✅ | ✅ |
| Custom property mapping | ✅ | ✅ |
| Async mapping | ✅ | ✅ |
| Caching | ✅ | ❌ |
| Validation | ✅ | ❌ |
| DI integration | Manual | Built-in |
formatDate, uppercase, etc.)Pull requests, discussions, and suggestions are welcome.
Open an issue or PR with a clear description of improvement.
MIT License
© 2025 Nishit Shiv
FAQs
A powerful, type-safe object mapping library for TypeScript and NestJS
We found that custom-automapper demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.