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 🧬

  • 2.1.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
5
decreased by-68.75%
Maintainers
1
Weekly downloads
 
Created
Source

🧬 Transmutant 🧬

A powerful, type-safe TypeScript library for transforming 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 transformation functions
  • High performance: Minimal overhead and zero dependencies
  • 🔄 Extensible: Support for custom transformation 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 transformation schema
const schema: Schema<User, UserDTO>[] = [
  {
    to: 'fullName',
    from: ({ source }) => `${source.firstName} ${source.lastName}`
  },
  {
    from: 'email',
    to: 'contactEmail'
  }
];

// Transform 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 transformation 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 transformation function that produces the correct type for that target property.

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

Transformation 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 Transformation Functions

Transform 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 Transformations

Include additional context in transformations:

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 transformation 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  // Transformation 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 transformations as needed

API Reference

transmute<Source, Target, TExtra = unknown>

Main transformation function.

Parameters
ParameterTypeDescription
schemaSchema<Source, Target, TExtra>[]Array of transformation rules
sourceSourceSource object to transform
extra?TExtraOptional additional data
Returns

Returns an object of type Target.

Type Definitions

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

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

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

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 30 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