Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>TS MacroNew to Visual Studio Code? Get it now.
TS Macro

TS Macro

zhiyuanzmj

|
67 installs
| (1) | Free
Define TS(X) macro powered by Volar.js
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

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, replaceRange } from 'ts-macro'
    
    const defineStylePlugin = createPlugin<{ macro: string } | undefined>(
      (
        { ts, compilerOptions },
        userOptions = vueCompilerOptions?.defineStyle ?? {
          macro: 'defineStyle',
        }, // Default options
      ) => {
        return {
          name: 'volar-plugin-define-style',
          resolveVirtualCode({ ast, codes }) {
            codes.push(
              `declare function ${userOptions.macro}<T>(style: string): T `,
            )
    
            ast.forEachChild(function walk(node) {
              if (
                ts.isCallExpression(node) &&
                node.expression.getText(ast) === userOptions.macro
              ) {
                // Add generic type for defineStyle.
                replaceRange(
                  codes,
                  node.arguments.pos - 1,
                  node.arguments.pos - 1,
                  // For simple cases, use strings instead of regex to generate types.
                  '<{ foo: string }>',
                )
              }
              node.forEachChild(walk)
            })
          },
        }
      },
    )
    
    export default {
      plugins: [
        defineStylePlugin({
          macro: 'defineStyle',
        }),
      ],
    }
    
    Compatible with Vue

    For Vue, your should import getText and getStart from ts-macro, and use ts.forEachChild instead of node.forEachChild. Relation issue: https://github.com/volarjs/volar.js/issues/165

    // tsm.config.ts
    
    import { createPlugin, getText, replaceSourceRange } from 'ts-macro'
    
    const defineStylePlugin = createPlugin<{ macro: string } | undefined>(
      (
        { ts, compilerOptions, vueCompilerOptions },
        userOptions = vueCompilerOptions?.defineStyle ?? {
          macro: 'defineStyle',
        }, // Default options
      ) => {
        return {
          name: 'volar-plugin-define-style',
          resolveVirtualCode({ ast, codes, source }) {
            codes.push(
              `declare function ${userOptions.macro}<T>(style: string): T `,
            )
    
            ts.forEachChild(ast, function walk(node) {
              if (
                ts.isCallExpression(node) &&
                getText(node.expression, ast, ts) === userOptions.macro
              ) {
                // Add generic type for defineStyle.
                replaceSourceRange(
                  codes,
                  // In vue file will be 'script' | 'scriptSetup', in ts file will be undefined.
                  source,
                  node.arguments.pos - 1,
                  node.arguments.pos - 1,
                  // For simple cases, use strings instead of regex to generate types.
                  '<{ foo: string }>',
                )
              }
              ts.forEachChild(node, walk)
            })
          },
        }
      },
    )
    
    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.

  • https://github.com/volarjs/volar.js
  • https://github.com/vue-vine/vue-vine
  • https://kermanx.github.io/reactive-vscode
  • https://github.com/vue-macros/vue-macros

Who are using ts-macro

  • https://github.com/vuejs/vue-jsx-vapor
  • https://github.com/vue-macros/vue-macros
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2025 Microsoft