-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[ID-Prep] PR2 - Preserve all type triple slash references #57440
Conversation
@@ -254,11 +257,11 @@ export function transformDeclarations(context: TransformationContext) { | |||
let needsScopeFixMarker = false; | |||
let resultHasScopeMarker = false; | |||
let enclosingDeclaration: Node; | |||
let necessaryTypeReferences: Set<[specifier: string, mode: ResolutionMode]> | undefined; | |||
let necessaryTypeReferences: Map<ModeAwareCacheKey, [specifier: string, mode: ResolutionMode]> | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we keep all references as they are declared in source, we can't use the tuple as the key because:
- We mark all source references as necessary upfront.
- Even if the host can't resolve the reference, we should still preserve it to keep as close to the original source.
An alternate approach would be to ask the host for the [specifier, mode]
tuple. This approach however fells error prone, since even in current emit some of these tuples come from the host, while other are created in the declaration transform.
let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined; | ||
let lateStatementReplacementMap: Map<NodeId, VisitResult<LateVisibilityPaintedStatement | ExportAssignment | undefined>>; | ||
let suppressNewDiagnosticContexts: boolean; | ||
let exportedModulesFromDeclarationEmit: Symbol[] | undefined; | ||
let exportedModulesFromDeclarationEmit: Set<Symbol> | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did some minor cleanup. exportedModulesFromDeclarationEmit
could in practice contain a lot of suplicate symbols since a symbol was pushed for every usage of an import type. (In tests I found an example where there were 40 elements in the array but only 2 distinct ones. This is especially problematic since there is a test for the presence of a symbol in the array).
If this change is controversial I can revert it.
let refs: Set<SourceFile>; | ||
let libs: Set<string>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both of these were previously Map
, but for libs
only the keys are ever used. And for refs
I understand form a previous PR that using objects as keys is now preferred (I assume this code was left over from a time when this was not possible)
If this change is controversial I can revert it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I would rather we (or the tool doing the emit) error'd on triple-slash references under whatever emit mode requires these be preserved, rather than change our existing-long term behavior for all users. Triple slash references have a legacy, and we should probably avoid sweeping changes to their behavior - you can generally get the compiler to do the same thing with a types
compiler option or an actual import, without all the funny elision/lifting/copying behavior.
Minimally, this feels potentially very breaky on very old codebases that somehow rely on the elision.
It certainly feels that way, but we have used them as the answer for loading global types in a few places, and it might be difficult to for developers to adopt that. If we don't preserve the A tempting alternative is to introduce import type "yadda"; // oops, this wasn't needed for the `.d.ts` file!
export function foo(arg: any) {
return (arg as SomeGlobalType).someValue;
} |
@weswigham Our initial approach was to forbid them altogether. The problem is that ambient module declarations will not be resolvable if there are no
The problem is if we want to emit declarations one file at a time, we can't know what However, declaration emit also currently removes So to summarize, regarding triple slash directives we can:
|
I think we’re missing an option:
However, I’m not convinced the exact rules for triple-slash elision/addition are super correct or desirable, and I’m pretty suspicious that any library authors would be manually writing them and then relying on their elision. I’m in favor of this change as is. I think the risks are fairly low. |
@@ -579,7 +590,7 @@ export function transformDeclarations(context: TransformationContext) { | |||
|
|||
function mapReferencesIntoArray(references: FileReference[], outputFilePath: string): (file: SourceFile) => void { | |||
return file => { | |||
if (exportedModulesFromDeclarationEmit?.includes(file.symbol)) { | |||
if (exportedModulesFromDeclarationEmit?.has(file.symbol)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this not prevent inclusion of manually-written triple-slash references that are redundant with imports?
But this PR makes that same "gotchya" apply to |
I don't entirely agree, but I am willing to try the change in 5.5. We will have to note this as a significant change though because it means that if a library author used something like |
I would be fine with issuing a checker error to ensure |
Then we run into another: What if a triple-slash reference is necessary for the implementation but not for the declaration. (some symbol is used in the code but does not make it into the declaration). I am ok with this limitation. I can't think of an example where we want someone to use a triple-slash reference instead of an import in a modern code base. The other reason I didn't go the error route is that we generally tried to make isolated declaration errors detectable by the external tool. (Although there are still some isolated declaration errors that can't be detected by an external tool, especially around computed properties). |
The TypeScript team hasn't accepted the linked issue #57439. If you can get it accepted, this PR will have a better chance of being reviewed. |
Trying to summarize the possible options after yesterday’s meeting. Backing up, the invariant we want to achieve is that a standalone isolated declaration emitter can produce declaration emit containing the same set of triple-slash references that
These aren’t strictly the only options and they aren’t totally mutually exclusive—this PR, for example, changes the behavior of The larger question embedded in option (1) is whether declaration emit (with or without the existence of |
Superseded by #57681 |
This is fix is part of the effort to get typescript emit closer to what an external tool could emit with isolated declarations.
Fixes #57439