microsoft/typescript-go · error · Error

Found external imports in .d.ts files:\n${importErrors.map(e

Error message

Found external imports in .d.ts files:\n${importErrors.map(e => "  " + e).join("\n")}

What it means

Thrown by the native-preview npm packaging task in Herebyfile.mjs after the JS API build (`npm run -w @typescript/native-preview build`) is copied into the package. It scans every dist/**/*.d.ts line-by-line for `import`/`export ... from` declarations and dynamic `import()` specifiers that are neither relative (".") nor subpath imports ("#"), and fails the build if any are found. The guard exists because the shipped platform packages set `dependencies: undefined` (Herebyfile.mjs:1958), so an external type import would be unresolvable for consumers.

Source

Thrown at Herebyfile.mjs:1948

    for (const dtsFile of dtsFiles) {
        const content = await fs.promises.readFile(dtsFile, "utf-8");
        const relPath = path.relative(mainPackageDir, dtsFile);
        for (const [i, line] of content.split("\n").entries()) {
            // Match: import ... from "specifier" / export ... from "specifier"
            const fromMatch = line.match(/(?:import|export)\s.*?\sfrom\s+["']([^"']+)["']/);
            if (fromMatch && !fromMatch[1].startsWith(".") && !fromMatch[1].startsWith("#")) {
                importErrors.push(`${relPath}:${i + 1}: external import declaration "${fromMatch[1]}"`);
            }
            // Match: import("specifier")
            for (const m of line.matchAll(/import\(["']([^"']+)["']\)/g)) {
                if (!m[1].startsWith(".") && !m[1].startsWith("#")) {
                    importErrors.push(`${relPath}:${i + 1}: external dynamic import "${m[1]}"`);
                }
            }
        }
    }
    if (importErrors.length) {
        throw new Error(`Found external imports in .d.ts files:\n${importErrors.map(e => "  " + e).join("\n")}`);
    }

    const extraFlags = getReleaseBuildFlags(options.setPrerelease || nativePreviewReleaseVersion ? getVersion() : undefined);

    const platformBuilders = platforms.map(({ npmDir, npmPackageName, nodeOs, nodeArch, goos, goarch }) => async () => {
        const packageJson = {
            ...inputPackageJson,
            bin: undefined,
            files: ["lib", "NOTICE.txt"],
            imports: undefined,
            dependencies: undefined,
            name: npmPackageName,
            os: [nodeOs],
            cpu: [nodeArch],
            exports: {
                "./package.json": "./package.json",
            },
        };

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Read the file:line entries listed in the error message, open the offending dist .d.ts, and trace the specifier back to the source file whose types leaked the external import
  2. Make the shipped declaration self-contained: declare the needed shape locally in source, or import it via a relative path / "#subpath" import so the emitted .d.ts only references "."/"#" specifiers
  3. If the type should be bundled, fix the dts-bundling JS API build (`npm run -w @typescript/native-preview build`) so it inlines the dependency's types, then rebuild
  4. Re-run the hereby packaging task and confirm the scan passes

Example fix

// before (source whose types ship in dist)
import type { CancellationToken } from "vscode-jsonrpc";
export function doWork(token: CancellationToken): void;

// after — declare the used shape locally so the .d.ts stays self-contained
interface CancellationToken { isCancellationRequested(): boolean; }
export function doWork(token: CancellationToken): void;
Defensive patterns

Strategy: validation

Validate before calling

// Run the same scan the build uses, before invoking the packaging task
import glob from "glob";
import fs from "node:fs";
import path from "node:path";

function findExternalDtsImports(pkgDir) {
  const errors = [];
  for (const f of glob.sync(`${pkgDir}/dist/**/*.d.ts`)) {
    const rel = path.relative(pkgDir, f);
    const lines = fs.readFileSync(f, "utf8").split("\n");
    lines.forEach((line, i) => {
      const m = line.match(/(?:import|export)\s.*?\sfrom\s+["']([^"']+)["']/);
      if (m && !m[1].startsWith(".") && !m[1].startsWith("#")) errors.push(`${rel}:${i + 1}: ${m[1]}`);
      for (const d of line.matchAll(/import\(["']([^"']+)["']\)/g)) {
        if (!d[1].startsWith(".") && !d[1].startsWith("#")) errors.push(`${rel}:${i + 1}: dynamic ${d[1]}`);
      }
    });
  }
  return errors;
}
// if (findExternalDtsImports("built/package").length) fail fast with details

Prevention

When it happens

Trigger: Running the native-preview package build or `native-preview:release` when a generated .d.ts under the package's dist/ contains something like `import type { X } from "vscode-jsonrpc";` or `import("some-package")` — i.e. the dts-bundling step did not inline a dependency's types into the shipped declarations.

Common situations: A source file in _packages imports types from an npm dependency (e.g. vscode-jsonrpc) without the bundler inlining it; a change to the JS API build/bundler config that stops inlining external types; adding a package.json dependency that is used in public API types but not wired into the dts-bundle step.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/80cd0fe7e2efee0e. Report an issue: GitHub.