notes/typescript/module-resolution.md
Module resolution searches TypeScript, declaration, JavaScript, and, when enabled, JSON extensions independently of allowJs (resolver extension masks); the program builder separately decides which discovered JavaScript files become inputs (filtering).
Known emitted extensions are substituted before implicit extensions are appended: ./value.js can resolve to value.ts, value.tsx, value.d.ts, then value.js (candidate table), while non-ESM modes can subsequently append extensions to the original candidate (resolution flow).
Without resolveJsonModule, an explicit .json request can progress to appended .json.js and .json.jsx candidates (trace fixture). Ancestor node_modules lookup searches TypeScript/declaration files before a separate JavaScript fallback pass (trace, implementation).
For dependency/subpath, TypeScript first identifies dependency as the package root and looks for a manifest at the physical subpath. It uses that nested manifest only when the dependency root has no exports map; a root map is authoritative (5.5.2, 6.0.3).
The nested manifest contributes types/typings and main, not exports. The resolver tries those package fields before an index candidate; an index is only a fallback outside ESM mode (5.5.2, 6.0.3). This is compiler resolution behavior, not a claim that Node ESM supports folder mains.