microsoft / microsoft/TypeScript

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

Abierto
#64,069 0 comentarios 0 reacciones 1 asignado Ver en GitHub

@andrewbranch ya está trabajando en esto.

Desde el 28/8/2026.

API Request
Lenguaje dominante
Go
Estrellas
111k
Forks
14.3k
Merge medio
2 d 4 h
PR fusionados (30 d)
132

Descripción

### 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`).

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.