TypeScript / Editorial solution guide
Fix imports that check but fail at runtime
Align compiler resolution with the actual module host and inspect emitted specifiers instead of assuming paths rewrites JavaScript.
Read-only knowledge base ยท No public comments
Recognize the symptoms
tsc or an editor resolves an alias, yet Node reports a missing module when loading the emitted program. Conversely, the checker can report an unresolved import even when a bundler has its own runtime mapping. Exact error wording varies by module format and runtime version, so preserve the original diagnostic and emitted import.
The failure can appear only after a clean build, packaging, or deployment because a development runner previously supplied an alias hook. A source-tree success does not establish that a plain emitted entry point has the same resolver.
Understand the likely causes
- paths describes how the checker can locate source or declarations; it does not normally rewrite the emitted alias into a relative file. The runtime or bundler needs compatible support. moduleResolution selects a checking model, while module and package metadata affect emitted or interpreted module form. These settings must describe the actual host rather than be chosen merely because they silence one diagnostic.
- ESM versus CommonJS, relative file extensions, package exports, case sensitivity, missing build files, and inaccurate declaration entry points can produce related symptoms. Inspect the exact configuration used by the failing command, not only the editor project or a different development tsconfig.
Inspect checker and runtime resolution separately
Record compiler and Node versions, the selected tsconfig, package.json type, source import, and emitted JavaScript. Resolution tracing can show which source file the checker selects, but cannot prove the runtime knows the alias. The dependency snippet below demonstrates a checker mapping for a small CommonJS fixture. It is not independently runnable: it requires the two source files and the build/run commands described here. No missing-module stack trace is fabricated.
{"compilerOptions":{"strict":true,"target":"ES2022","module":"CommonJS","moduleResolution":"Node","baseUrl":".","paths":{"@app/*":["src/*"]},"outDir":"dist"},"include":["src/**/*.ts"]}
Configuration for the dependent fixture; paths does not install a Node alias resolver.
Identify the implementation the alias refers to
Create src/math.ts with the exported operation below. The problematic caller import would be import { double } from "@app/math"; the checker mapping can find this source, while ordinary CommonJS output retains a require for that package-like name. Merely adding an ambient declare module would add another checker claim, not make the host locate math.js. Confirm the implementation is emitted and included in the package before changing unrelated dependencies.
export function double(value: number): number { return value * 2; }
Source dependency for the fixture; not a standalone entry point.
Choose a path the selected host actually loads
For this explicit CommonJS fixture, change src/main.ts to the relative import below. Compile both files with the configuration and run dist/main.js in a CommonJS package context; the line is 8. The relative specifier is preserved in a form Node can load beside the emitted math.js. An ESM NodeNext fixture would need its own aligned configuration and extension policy, commonly an emitted .js relative specifier. Do not copy the CommonJS extension rule blindly into a different host.
import { double } from "./math";
console.log(double(4));
Corrected dependent entry point; expected fixture output is 8 followed by a newline.
Verify the fix
In an isolated temporary directory, create all three shown files and a package.json declaring type commonjs. Run the pinned compiler with -p tsconfig.json, then Node on dist/main.js. Confirm both successful checking and the exact line 8; inspect emitted imports rather than stopping at the checker result.
If aliases are intentionally retained, test the documented resolver in the actual production command and packed artifact. A development-only hook or editor setting is not equivalent evidence. Keep the failing configuration as a minimal regression fixture.
Keep it from recurring
- Choose module settings from the deployment host, keep source/output paths explicit, and run emitted entry points in checks. Document any alias mechanism and avoid wildcard ambient declarations as runtime-load fixes.