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
- 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
- Strip types before the plugin runs (feed JS output, or run a prior transform pass) so type annotations are never traversed
- 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
- Always override visitTsType in legacy Visitor subclasses, even as a pass-through
- Keep legacy JS plugins away from .ts inputs, or strip types before the plugin stage
- Migrate legacy plugins to the current visitor API, which traverses TS nodes natively
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
- Unknown statement type: ${(stmt as any).type
- Duplicated element (${elements[j].key})
- empty expression container
- illegal conversion: Cannot convert {:?} to ModuleDeclaration
- unable to access unknown nodes
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/5ae44aac42a60a39.
Report an issue: GitHub.