Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

transmutant

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

transmutant

Powerful type transmutations for TypeScript 🧬

  • 3.0.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
6
increased by200%
Maintainers
1
Weekly downloads
 
Created
Source

🧬 Transmutant 🧬

A powerful, type-safe TypeScript library for transmuting objects through flexible schema definitions.

npm version License: MIT GitHub issues GitHub stars

Features

  • 🔒 Type-safe: Full TypeScript support with strong type inference
  • 🎯 Flexible mapping: Direct property mapping or custom transmutation functions
  • High performance: Minimal overhead and zero dependencies
  • 🔄 Extensible: Support for custom transmutation logic and external data
  • 📦 Lightweight: Zero dependencies, small bundle size
  • 🛠️ Predictable: Transparent handling of undefined values

Installation

npm install transmutant

Quick Start

import { transmute, Schema } from 'transmutant';

// Source type
interface User {
  firstName: string;
  lastName: string;
  email: string;
}

// Target type
interface UserDTO {
  fullName: string;
  contactEmail: string;
}

// Define transmutation schema
const schema: Schema<User, UserDTO>[] = [
  {
    to: 'fullName',
    from: ({ source }) => `${source.firstName} ${source.lastName}`
  },
  {
    from: 'email',
    to: 'contactEmail'
  }
];

// Transmut the object
const user: User = {
  firstName: 'John',
  lastName: 'Doe',
  email: 'john@example.com'
};

const userDTO = transmute(schema, user);
// Result: { fullName: 'John Doe', contactEmail: 'john@example.com' }

Core Concepts

Schema Definition

A schema is an array of transmutation rules that define how properties should be mapped from the source to the target type. Each rule specifies the target property key and either a source property key for direct mapping or a transmutation function that produces the correct type for that target property.

type Schema<Source, Target, Extra = unknown> = {
  [TargetKey in keyof Target]: {
    /** Target property key */
    to: TargetKey
    /** Source property key for direct mapping or a custom transmutation function */
    from: keyof Source | TransmuteFn<Source, Target, TargetKey, Extra>
  }
}[keyof Target]

Transmutation Types

1. Direct Property Mapping

Map a property directly from source to target:

interface Source {
  email: string;
}

interface Target {
  contactEmail: string;
}

const schema: Schema<Source, Target>[] = [
  { from: 'email', to: 'contactEmail' }
];
2. Custom Transmutation Functions

Transmute properties using custom logic with type safety:

interface Source {
  age: number;
}

interface Target {
  isAdult: boolean;
}

const schema: Schema<Source, Target>[] = [
  {
    to: 'isAdult',
    from: ({ source }) => source.age >= 18
  }
];
3. External Data Transmutations

Include additional context in transmutations:

interface Source {
  price: number;
}

interface Target {
  formattedPrice: string;
}

interface ExtraData {
  currency: string;
}

const schema: Schema<Source, Target, ExtraData>[] = [
  {
    to: 'formattedPrice',
    from: ({ source, extra }) =>
      `${source.price.toFixed(2)} ${extra.currency}`
  }
];

Handling Undefined Values

When a source property doesn't exist or a transmutation function returns undefined, the target property will remain undefined:

interface Source {
  existingField: string;
}

interface Target {
  mappedField: string;
  computedField: string;
}

const schema: Schema<Source, Target>[] = [
  {
    from: 'nonExistentField' as keyof Source,  // Property doesn't exist
    to: 'mappedField'
  },
  {
    to: 'computedField',
    from: ({ source }) => undefined  // Transmutation returns undefined
  }
];

const result = transmute(schema, { existingField: 'value' });
// Result: { mappedField: undefined, computedField: undefined }

This allows you to:

  • Distinguish between unset values (undefined) and explicitly set null values
  • Handle optional properties naturally
  • Process partial transmutations as needed

API Reference

transmute<Source, Target, Extra = unknown>

Main transmutation function.

Parameters
ParameterTypeDescription
schemaSchema<Source, Target, Extra>[]Array of transmutation rules
sourceSourceSource object to transmut
extra?ExtraOptional additional data
Returns

Returns an object of type Target.

Type Definitions

/**
 * Schema entry defining how a property should be transmuted
 */
type Schema<Source, Target, Extra = unknown> = {
  [TargetKey in keyof Target]: {
    /** Target property key */
    to: TargetKey
    /** Source property key for direct mapping or a custom transmutation function */
    from: keyof Source | TransmuteFn<Source, Target, TargetKey, Extra>
  }
}[keyof Target]

/**
 * Function that performs property transmutation
 */
type TransmuteFn<Source, Target, TargetKey extends keyof Target, Extra = unknown> =
  (args: TransmuteFnArgs<Source, Extra>) => Target[TargetKey]

/**
 * Arguments passed to transmutation function
 */
type TransmuteFnArgs<Source, Extra> = {
  source: Source
  extra?: Extra
}

Type Safety Examples

interface Source {
  firstName: string;
  lastName: string;
  age: number;
}

interface Target {
  fullName: string;    // TargetKey = 'fullName', type = string
  isAdult: boolean;    // TargetKey = 'isAdult', type = boolean
}

// TypeScript enforces correct return types
const schema: Schema<Source, Target>[] = [
  {
    to: 'fullName',
    from: ({ source }) => `${source.firstName} ${source.lastName}`  // Must return string
  },
  {
    to: 'isAdult',
    from: ({ source }) => source.age >= 18  // Must return boolean
  }
];

// Type error example:
const invalidSchema: Schema<Source, Target>[] = [
  {
    to: 'isAdult',
    from: ({ source }) => source.age  // Type error: number is not assignable to boolean
  }
];

Direct Property Mapping

When using direct property mapping, TypeScript ensures type compatibility:

interface Source {
  email: string;
  age: number;
}

interface Target {
  contactEmail: string;
  yearOfBirth: number;
}

const schema: Schema<Source, Target>[] = [
  { from: 'email', to: 'contactEmail' },     // OK: string -> string
  { from: 'age', to: 'yearOfBirth' }         // OK: number -> number
];

Using Extra Data

Extra data is fully typed:

interface ExtraData {
  currentYear: number;
}

interface Source {
  age: number;
}

interface Target {
  yearOfBirth: number;
}

const schema: Schema<Source, Target, ExtraData>[] = [
  {
    to: 'yearOfBirth',
    from: ({ source, extra }) => extra.currentYear - source.age
  }
];

const result = transmute(schema, { age: 25 }, { currentYear: 2024 });

Contributing

Contributions are welcome! Feel free to submit a Pull Request.

License

MIT © Antoni Oriol


Built with ❤️ by Antoni Oriol

Keywords

FAQs

Package last updated on 31 Oct 2024

Did you know?

Socket

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc