swc-project/swc · error · Error

Method visitTsType not implemented.

Error message

Method visitTsType not implemented.

What it means

The legacy JavaScript `Visitor` in @swc/core declares visitTsType but its base implementation only throws. TypeScript type nodes are reached via visitTsTypeAnnotation -> visitTsType whenever the traversal walks annotated nodes (function parameters, arrow return types, variable annotations). Any legacy-plugin visit of a TypeScript AST containing type annotations therefore crashes on the first type node unless the subclass overrides visitTsType.

Source

Thrown at packages/core/src/Visitor.ts:1734

        }
        if (n.default) {
            n.default = this.visitTsType(n.default);
        }
        n.name = this.visitIdentifierReference(n.name);
        return n;
    }

    visitTsTypeAnnotation(
        a: TsTypeAnnotation | undefined
    ): TsTypeAnnotation | undefined {
        if (a) {
            a.typeAnnotation = this.visitTsType(a.typeAnnotation);
        }
        return a;
    }

    visitTsType(n: TsType): TsType {
        throw new Error("Method visitTsType not implemented.");
    }

    visitPatterns(nodes: Pattern[]): Pattern[] {
        return nodes.map(this.visitPattern.bind(this));
    }

    visitImportDeclaration(n: ImportDeclaration): ImportDeclaration {
        n.source = this.visitStringLiteral(n.source);
        n.specifiers = this.visitImportSpecifiers(n.specifiers || []);
        return n;
    }

    visitImportSpecifiers(nodes: ImportSpecifier[]): ImportSpecifier[] {
        return nodes.map(this.visitImportSpecifier.bind(this));
    }

    visitImportSpecifier(node: ImportSpecifier): ImportSpecifier {
        switch (node.type) {

View on GitHub (pinned to 5176682b65)

Solutions

  1. Override visitTsType in your subclass to return the node unchanged (`return n`), or deep-visit its variant if you actually need to mutate type nodes
  2. Strip types before the plugin runs (feed JS output, or run a prior transform pass) so type annotations are never traversed
  3. Migrate the plugin to the current visitor API, which handles TS nodes natively

Example fix

// before
class MyVisitor extends Visitor {}
// -> Error: Method visitTsType not implemented.

// after
class MyVisitor extends Visitor {
    visitTsType(n) {
        return n; // leave type nodes untouched
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

// Detect TypeScript type nodes before visiting so you can skip or strip them.
function hasTsTypeNodes(program) {
  return /"TsKeywordType"|"TsTypeReference"|"TsTypeAnnotation"/.test(JSON.stringify(program));
}

Try / catch

try {
  program = new MyVisitor().visitProgram(program);
} catch (e) {
  if (e instanceof Error && /visitTsType not implemented/.test(e.message)) {
    // subclass forgot the override — degrade to the untransformed program
    return program;
  }
  throw e;
}

Prevention

When it happens

Trigger: A legacy plugin visitor transforming a TS file with annotations such as `const x: number = 1` or `(a: string) => a`; arrow functions carrying returnType/typeParameters; any path reaching visitTsTypeAnnotation with a non-empty annotation while the subclass does not override visitTsType.

Common situations: Reusing an old JS plugin (written against plain JS) on .ts inputs after a monorepo migrates to TypeScript; enabling an existing legacy plugin for test fixtures that now include typed files.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/5ae44aac42a60a39. Report an issue: GitHub.