Skip to content

[FEATURE] Extend Native Macros in ts-macros for Safer Type Inference and Compile-Time Transformations #92

@rubeniskov

Description

@rubeniskov

Is your feature request related to a problem? Please describe.

I would like to extend the native macros in ts-macros to provide more complex macros that can infer types and produce outputs at compile time. Currently, the $$raw macro allows for low-level AST manipulations but can be harmful as it has system-level access, which is a concern for security and stability. I want to create macros that are sensitive to certain configurations, like noComptime, to restrict unsafe operations while still enabling powerful type inference and compile-time tooling.

For example, I would like to create a macro such as $$pick(props), which extracts properties from an argument based on a given type at compile time. This would be especially useful when working with React to deconstruct props and streamline prop drilling across components.

Describe the solution you'd like

I propose extending the ts-macros transformer with a configurable system for defining new macros at a lower level, ensuring that these macros respect specific configurations such as noComptime. This would allow developers to create powerful, type-inferable macros that perform compile-time transformations while restricting dangerous or unwanted operations like those enabled by $$raw.

This can be achieved with the exposure of the nativeMacros map and allowing a new argument in the MacroTransformer liek this

import nativeMacros, { NativeMacro } from 'ts-macros/dist/nativeMacros';
import { Macro, MacroTransformer } from 'ts-macros/dist/transformer';
import * as ts from 'typescript';

export const macros = new Map<ts.Symbol, Macro>([]);

const customNativeMacros: Record<string, NativeMacro> = {
  ...nativeMacros,
  $$pick: {
    call(args, transformer, callSite) {
      // The logic of the macro
    },
  },
};

export interface TsMacrosConfig {
  noComptime?: boolean;
  watchMode?: boolean;
  keepImports?: boolean;
  logFileData?: boolean;
  // Custom options
}

const transformer =
  (program: ts.Program, config?: TsMacrosConfig): ts.TransformerFactory<ts.Node> =>
  (ctx) => {
    const typeChecker = program.getTypeChecker();
    const transformer = new MacroTransformer(ctx, typeChecker, macros, customNativeMacros, {
      ...config,
      noComptime: config?.noComptime ?? false,
    });
    return (firstNode) => {
      return transformer.run(firstNode as ts.SourceFile);
    };
  };

export default transformer;

Additional context

This feature would allow developers to create safer, more powerful macros that enhance TypeScript’s compile-time capabilities while avoiding the potential risks of $$raw. It would also facilitate macros tailored for specific use cases, such as React component prop management, enabling clean, type-safe code.

This feature request outlines the need for safer, configurable macros with type inference capabilities while emphasizing security considerations when extending native macros like $$raw.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions