API Stability Notice

Macroforge is under active development. The API is not yet stable and may change between versions. Some documentation sections may be outdated.

Clone

The Clone macro generates a clone() method for deep copying objects. This is analogous to Rust’s Clone trait, providing a way to create independent copies of values.

Generated Output

TypeGenerated CodeDescription
ClassclassNameClone(value) + static clone(value)Standalone function + static wrapper method
EnumenumNameClone(value: EnumName): EnumNameStandalone function (enums are primitives, returns value as-is)
InterfaceinterfaceNameClone(value: InterfaceName): InterfaceNameStandalone function creating a new object literal
Type AliastypeNameClone(value: TypeName): TypeNameStandalone function with spread copy for objects

Cloning Strategy

The generated clone performs a shallow copy of all fields:

  • Primitives (string, number, boolean): Copied by value
  • Objects: Reference is copied (not deep cloned)
  • Arrays: Reference is copied (not deep cloned)

For deep cloning of nested objects, those objects should also derive Clone and the caller should clone them explicitly.

Example

Before (Your Code)
/** @derive(Clone) */
class Point {
    x: number;
    y: number;
}
After (Generated)
class Point {
    x: number;
    y: number;

    static clone(value: Point): Point {
        return pointClone(value);
    }
}

export function pointClone(value: Point): Point {
    const cloned = Object.create(Object.getPrototypeOf(value));
    cloned.x = value.x;
    cloned.y = value.y;
    return cloned;
}

Generated output:

class Point {
    x: number;
    y: number;

    static clone(value: Point): Point {
        return pointClone(value);
    }
}

export function pointClone(value: Point): Point {
    const cloned = Object.create(Object.getPrototypeOf(value));
    cloned.x = value.x;
    cloned.y = value.y;
    return cloned;
}

Implementation Notes

  • Classes: Uses Object.create(Object.getPrototypeOf(value)) to preserve the prototype chain, ensuring instanceof checks work correctly
  • Enums: Simply returns the value (enums are primitives in TypeScript)
  • Interfaces/Type Aliases: Creates new object literals with spread operator for union/tuple types, or field-by-field copy for object types