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
- 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
- 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
- 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
- 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
- Never let public API types import from external packages — declare needed shapes locally or via relative/#subpath imports
- Add a CI step that scans dist/**/*.d.ts for non-relative specifiers before the packaging task
- After adding a dependency, rebuild the JS API and grep the emitted .d.ts for external specifiers
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
- ${publishedTypeScriptAliasPackageName} should alias the type
- ${publishedTypeScriptAliasPackageName} package.json did not
- ${publishedTypeScriptAliasPackageName} package.json did not
- Could not find ${publishedTypeScriptAliasPackageName}; run n
- ${publishedTypeScriptAliasPackageName} does not depend on ${
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/80cd0fe7e2efee0e.
Report an issue: GitHub.