Skip to content

ts-macro/ts-macro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

98b2353 · Mar 29, 2025
Mar 11, 2025
Mar 10, 2025
Mar 29, 2025
Dec 14, 2024
Nov 1, 2024
Nov 1, 2024
Oct 20, 2024
Mar 12, 2025
Mar 29, 2025
Mar 10, 2025
Mar 10, 2025
Mar 10, 2025
Mar 10, 2025
Nov 1, 2024

Repository files navigation

TS Macro

NPM version

This is a VSCode plugin for define TS(X) macro powered by Volar.js.

Usage

  1. Install the VSCode Plugin, or use a REPL that supports ts-macro.

  2. Create tsm.config.ts at the same level of tsconfig.json.

    TS Macro supports automatic registration of Volar plugins from vite.config.ts, similar to xxx.d.ts.
    For plugin authors, you need to export a volar file, and TS Macro will automatically load the plugin and share userOptions with the vite plugin. Example.
    For plugin users, you only need to install the TS Macro VSCode plugin, and there's no need to write tsm.config.ts.

  3. Writing your first plugin.

    // tsm.config.ts
    export default {
      plugins: [
        {
          name: 'ts-macro-define-style',
          resolveVirtualCode({ codes }) {
            // declare the `defineStyle` function type for every TS(X) files.
            codes.push('declare function defineStyle<T>(style: string): T ')
          },
        },
      ],
    }

    Or You can use createPlugin to define plugin. also compatibility with @vue/language-tools plugin.

    // tsm.config.ts
    import { createPlugin, replaceSourceRange } from 'ts-macro'
    
    const defineStylePlugin = createPlugin<{ macro: string } | undefined>(
      (
       { 
         ts, 
         compilerOptions, 
         vueCompilerOptions // only useful in '@vue/language-tools'
       }, 
       userOptions = vueCompilerOptions?.defineStyle ?? { macro: 'defineStyle' } // default options
     ) => {
        return {
          name: 'ts-macro-define-style',
          resolveVirtualCode({ ast, codes, source }) {
            codes.push(
              `declare function ${userOptions.macro}<T>(style: string): T `,
            )
    
            ts.forEachChild(ast, walk)
    
            function walk(
              node: import('typescript').Node,
            ) {
              ts.forEachChild(node, walk)
    
              if (
                ts.isCallExpression(node) &&
                node.expression.getText(ast) === userOptions.macro
              ) {
                // add generic type for defineStyle.
                // if your plugin don't support vue file, you can use replaceRange instead.
                replaceSourceRange(
                  codes,
                  // in vue file will be 'script' | 'scriptSetup', in ts file will be undefined.
                  source,
                  node.arguments.pos - 1,
                  node.arguments.pos - 1,
                  // should be use regex to generate type, for simple use string instead.
                  '<{ foo: string }>',
                )
              }
            }
          },
        }
      },
    )
    
    export default {
      plugins: [
        defineStylePlugin({
          macro: 'defineStyle',
        }),
      ],
    }
  4. Result

    image

Full implementation: define-style

TSC

Use tsmc instead of tsc to compile TS.

Install

pnpm add @ts-macro/tsc -D

Usage in package.json.

{
  "scripts": {
    "typecheck": "tsmc --noEmit"
  }
}

References

Thanks for these great projects, I have learned a lot from them.

Who are using ts-macro