microsoft / microsoft/TypeScript

[API] No module resolution API: no counterpart to ts.resolveModuleName

Offen
#64,069 0 Kommentare 0 Reaktionen 1 zugewiesene Person Auf GitHub ansehen

@andrewbranch arbeitet bereits daran.

Seit 28.8.2026.

API Request
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

### Description

The 7.x API has no counterpart to `ts.resolveModuleName`, and no other way to ask "what does this specifier resolve to from this file?". The compiler does the resolution internally when it builds a program, but a consumer cannot invoke it on its own.

That matters for tools that resolve outside of, or ahead of, a program:

- Finding a package's declaration entry from its directory, so that `exports` conditions, `typesVersions` and the `types`/`typings` fallbacks all apply — the thing `ts.resolveModuleName(manifest.name, path.join(dir, "__entry__.ts"), options, host)` answered in one call.
- Reporting where an import would resolve to, without materialising a program for it.
- Deciding which files to load before opening a project.

The roadmap in #63875 covers `createProgram`, `createSourceFile`, `transpileModule` and `parseCommandLine` under "top-level utility APIs", but resolution is not among them. microsoft/typescript-go#455 named "resolution behavior" as one of the critical use cases the API was meant to serve, so I may simply have missed where this is tracked — if there is an existing issue, this can be closed as a duplicate.

### Why a workaround isn't sufficient

Reimplementing it means reimplementing Node's `exports` algorithm. I have done so for the narrow case of a package resolving its own name, and it is about 40 lines that handle condition maps, arrays and the `.`/subpath split:

```ts
function selectExportTarget(target: unknown, conditions: ReadonlySet): string | undefined {
if (typeof target === "string") return target;
if (Array.isArray(target)) {
for (const alternative of target) {
const selected = selectExportTarget(alternative, conditions);
if (selected) return selected;
}
return undefined;
}
if (target && typeof target === "object") {
for (const [condition, value] of Object.entries(target)) {
if (conditions.has(condition)) {
const selected = selectExportTarget(value, conditions);
if (selected) return selected;
}
}
}
return undefined;
}
```

That covers the fixtures I have and nothing more. It does not handle `typesVersions`, symlink realpath resolution (pnpm layouts), extension substitution, or `paths`. Every consumer that needs resolution will write a different subset, each wrong in a different way, and none will agree with the compiler that ultimately type-checks the code.

### Suggested shape

Something close to the 6.x signature, answering from the same implementation the compiler uses:

```ts
resolveModuleName(
moduleName: string,
containingFile: string,
compilerOptions: CompilerOptions,
): { resolvedFileName: string; isExternalLibraryImport: boolean; extension: string } | undefined
```

A snapshot-scoped variant (`project.resolveModuleName(...)`) would work equally well for my case and might fit the existing model better, since options and the file system are already established there.

### Use case

Porting OpenRewrite's JavaScript/TypeScript parser from the 6.x API. One component enumerates the public types a package exports, and locates each package's declaration entry by resolving the package's own name from inside its directory. On 6.x that is a single `resolveModuleName` call; on 7.x it is the hand-rolled subset above, which loses `exports` maps that name declarations only under a condition the subset does not model.

Verified against `7.0.2` and `typescript@next` (`7.1.0-dev.20260827.1`).

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.