X Tutup
The Wayback Machine - https://web.archive.org/web/20250601141231/https://github.com/microsoft/TypeScript/pull/48386
Skip to content

Follow paths in triple-slash types references #48386

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

weswigham
Copy link
Member

Everyone I've spoken to seems to agree that ///<reference types comments not following the paths (and baseUrl) compiler options seems to be an oversight on our part.

Fixes an issue I brought up on our teams chat while doing work on #48278.

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Mar 23, 2022
@@ -354,7 +354,10 @@ namespace ts {
}
const conditions = features & NodeResolutionFeatures.Exports ? features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] : [];
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features, conditions };
let resolved = primaryLookup();
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
const optional = tryLoadModuleUsingOptionalResolutionSettings(Extensions.DtsOnly, typeReferenceDirectiveName, containingDirectory || "", loader, moduleResolutionState);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well paths uses baseUrl.. And then tryLoadModuleUsingOptionalResolutionSettings has some baseUrl and rootDirs logic as well.. wouldnt we want typeRoots instead of baseUrl and probably rootDirs as well for type reference directive

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's the case? Generally, the model we all have is that ///<reference types= resolves exactly like an import statement does. An import statement uses the full tryLoadModuleUsingOptionalResolutionSettings function, so I think we also should use it here.

(Plus, typeRoots is already explicitly handled when looking up @types names inside primaryLookup)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only 🤷‍♀️❓🤷‍♀️ kinda thing is weather a typeRoots resolution should have priority over a paths/baseUrl one or not. I'd argue that paths and baseUrl are more specific compiler options, so should have priority (hence this placement).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But typeRoots also is in compilerOption and i think is set when user prefers to resolve type reference directive from certain location.. When not set i agree that it baseUrl makes sense

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but typeRoots a list of potential directories, while paths is exact matches and baseUrl is a single directory. That's why paths > baseUrl > typeRoots makes sense to me. (typeRoots will never conflict with rootDirs as it were because typeRoots are only relevant for non-relative names, while rootDirs are only relevant for relative names)

@eps1lon
Copy link
Contributor

eps1lon commented Mar 29, 2022

Also relevant for mapping of older versions of @types/* dependencies e.g. DefinitelyTyped/DefinitelyTyped#59445

@@ -354,7 +354,10 @@ namespace ts {
}
const conditions = features & NodeResolutionFeatures.Exports ? features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] : [];
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features, conditions };
let resolved = primaryLookup();
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
const optional = tryLoadModuleUsingOptionalResolutionSettings(Extensions.DtsOnly, typeReferenceDirectiveName, containingDirectory || "", loader, moduleResolutionState);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is containingDirectory || host.getCurrentDirectory() better than containingDirectory || "" ?

Copy link
Member Author

@weswigham weswigham Apr 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe... nah, if anything you'd want the project root, I think. currentDirectory is never actually undefined in practice, however. The resolveTypeReferenceDirectiveNamesWorker it's always wrapped up into (in our uses, anyway) always passes a non-undefined containingFile, so I think it's mostly a quirk of the public signature.

const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
const optional = tryLoadModuleUsingOptionalResolutionSettings(Extensions.DtsOnly, typeReferenceDirectiveName, containingDirectory || "", loader, moduleResolutionState);
// tryLoadModuleUsingOptionalResolutionSettings will happily return what a user wrote in `paths` varbatim - this means if a user writes `.js`, it'll return a `.js` file, even if we're looking for TS files
let resolved = optional && hasTSFileExtension(optional.path) && { fileName: optional.path, packageId: optional.packageId } || primaryLookup();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we need to change auto addition of type reference directive during declaration emit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, those reuse resolutions found during program construction - so long as we initially make the non-relative name here, we should reuse it in declaration emit.

@sandersn
Copy link
Member

sandersn commented Apr 2, 2025

@weswigham is this PR worth keeping?

  • Are triple-slash references even used much these days?
  • I believe some of these tsconfig options are going away in TS6/TS7. Does that change anything?

@sandersn sandersn closed this Apr 30, 2025
@github-project-automation github-project-automation bot moved this from Waiting on reviewers to Done in PR Backlog Apr 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

5 participants
X Tutup