diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 18c3b6e1ec685..2e975397c1a49 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8472,17 +8472,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { cancellationToken.throwIfCancellationRequested(); } let hadError = false; + const { finalizeBoundary, startRecoveryScope } = createRecoveryBoundary(); const transformed = visitNode(existing, visitExistingNodeTreeSymbols, isTypeNode); - if (hadError) { + if (!finalizeBoundary()) { return undefined; } context.approximateLength += existing.end - existing.pos; return transformed; function visitExistingNodeTreeSymbols(node: Node): Node | undefined { + // If there was an error in a sibling node bail early, the result will be discarded anyway + if (hadError) return node; + const recover = startRecoveryScope(); const onExitNewScope = isNewScopeNode(node) ? onEnterNewScope(node) : undefined; const result = visitExistingNodeTreeSymbolsWorker(node); onExitNewScope?.(); + + // If there was an error, maybe we can recover by serializing the actual type of the node + if (hadError) { + if (isTypeNode(node) && !isTypePredicateNode(node)) { + recover(); + return serializeExistingTypeNode(context, node); + } + return node; + } // We want to clone the subtree, so when we mark it up with __pos and __end in quickfixes, // we don't get odd behavior because of reused nodes. We also need to clone to _remove_ // the position information if the node comes from a different file than the one the node builder @@ -8492,6 +8505,86 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result === node ? setTextRange(context, factory.cloneNode(result), node) : result; } + function createRecoveryBoundary() { + let unreportedErrors: (() => void)[]; + const oldTracker = context.tracker; + const oldTrackedSymbols = context.trackedSymbols; + context.trackedSymbols = []; + const oldEncounteredError = context.encounteredError; + context.tracker = new SymbolTrackerImpl(context, { + ...oldTracker.inner, + reportCyclicStructureError() { + markError(() => oldTracker.reportCyclicStructureError()); + }, + reportInaccessibleThisError() { + markError(() => oldTracker.reportInaccessibleThisError()); + }, + reportInaccessibleUniqueSymbolError() { + markError(() => oldTracker.reportInaccessibleUniqueSymbolError()); + }, + reportLikelyUnsafeImportRequiredError(specifier) { + markError(() => oldTracker.reportLikelyUnsafeImportRequiredError(specifier)); + }, + reportNonSerializableProperty(name) { + markError(() => oldTracker.reportNonSerializableProperty(name)); + }, + trackSymbol(sym, decl, meaning) { + const accessibility = isSymbolAccessible(sym, decl, meaning, /*shouldComputeAliasesToMakeVisible*/ false); + if (accessibility.accessibility !== SymbolAccessibility.Accessible) { + (context.trackedSymbols ??= []).push([sym, decl, meaning]); + return true; + } + return false; + }, + moduleResolverHost: context.tracker.moduleResolverHost, + }, context.tracker.moduleResolverHost); + + return { + startRecoveryScope, + finalizeBoundary, + }; + + function markError(unreportedError: () => void) { + hadError = true; + (unreportedErrors ??= []).push(unreportedError); + } + + function startRecoveryScope() { + const initialTrackedSymbolsTop = context.trackedSymbols?.length ?? 0; + const unreportedErrorsTop = unreportedErrors?.length ?? 0; + return () => { + hadError = false; + // Reset the tracked symbols to before the error + if (context.trackedSymbols) { + context.trackedSymbols.length = initialTrackedSymbolsTop; + } + if (unreportedErrors) { + unreportedErrors.length = unreportedErrorsTop; + } + }; + } + + function finalizeBoundary() { + context.tracker = oldTracker; + const newTrackedSymbols = context.trackedSymbols; + context.trackedSymbols = oldTrackedSymbols; + context.encounteredError = oldEncounteredError; + + unreportedErrors?.forEach(fn => fn()); + if (hadError) { + return false; + } + newTrackedSymbols?.forEach( + ([symbol, enclosingDeclaration, meaning]) => + context.tracker.trackSymbol( + symbol, + enclosingDeclaration, + meaning, + ), + ); + return true; + } + } function onEnterNewScope(node: IntroducesNewScopeNode | ConditionalTypeNode) { return enterNewScope(context, node, getParametersInScope(node), getTypeParametersInScope(node)); } @@ -8765,13 +8858,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function rewriteModuleSpecifier(parent: ImportTypeNode, lit: StringLiteral) { if (context.bundled || context.enclosingFile !== getSourceFileOfNode(lit)) { - const targetFile = getExternalModuleFileFromDeclaration(parent); - if (targetFile) { - const newName = getSpecifierForModuleSymbol(targetFile.symbol, context); - if (newName !== lit.text) { - return setOriginalNode(factory.createStringLiteral(newName), lit); + let name = lit.text; + const nodeSymbol = getNodeLinks(node).resolvedSymbol; + const meaning = parent.isTypeOf ? SymbolFlags.Value : SymbolFlags.Type; + const parentSymbol = nodeSymbol + && isSymbolAccessible(nodeSymbol, context.enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible + && lookupSymbolChain(nodeSymbol, context, meaning, /*yieldModuleSymbol*/ true)[0]; + if (parentSymbol && parentSymbol.flags & SymbolFlags.Module) { + name = getSpecifierForModuleSymbol(parentSymbol, context); + } + else { + const targetFile = getExternalModuleFileFromDeclaration(parent); + if (targetFile) { + name = getSpecifierForModuleSymbol(targetFile.symbol, context); } } + if (name.includes("/node_modules/")) { + context.encounteredError = true; + if (context.tracker.reportLikelyUnsafeImportRequiredError) { + context.tracker.reportLikelyUnsafeImportRequiredError(name); + } + } + if (name !== lit.text) { + return setOriginalNode(factory.createStringLiteral(name), lit); + } } return visitNode(lit, visitExistingNodeTreeSymbols, isStringLiteral)!; } diff --git a/tests/baselines/reference/declarationEmitUsingTypeAlias2.js b/tests/baselines/reference/declarationEmitUsingTypeAlias2.js new file mode 100644 index 0000000000000..eae2e3fd10241 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias2.js @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias2.ts] //// + +//// [inner.d.ts] +export declare type Other = { other: string }; +export declare type SomeType = { arg: Other }; + +//// [other.d.ts] +export declare const shouldLookupName: unique symbol; +export declare const shouldReuseLocalName: unique symbol; +export declare const reuseDepName: unique symbol; +export declare const shouldBeElided: unique symbol; +export declare const isNotAccessibleShouldError: unique symbol; + +//// [index.d.ts] +import { Other } from './inner' +import { shouldLookupName, reuseDepName, shouldReuseLocalName, shouldBeElided } from './other' +export declare const goodDeclaration: () => () => { + /** Other Can't be named in index.ts, but the whole conditional type can be resolved */ + shouldPrintResult: T extends Other? "O": "N", + /** Symbol shouldBeElided should not be present in index.d.ts, it might be since it's tracked before Other is seen and an error reported */ + shouldPrintResult2: T extends typeof shouldBeElided? Other: "N", + /** Specifier should come from module, local path should not be reused */ + shouldLookupName: typeof import('./other').shouldLookupName, + /** This is imported in index so local name should be reused */ + shouldReuseLocalName: typeof shouldReuseLocalName + /** This is NOT imported in index so import should be created */ + reuseDepName: typeof reuseDepName, +} +export { shouldLookupName, shouldReuseLocalName, reuseDepName, shouldBeElided }; + +//// [package.json] +{ + "name": "some-dep", + "exports": { + ".": "./dist/index.js" + } +} + +//// [index.ts] +import { goodDeclaration, shouldReuseLocalName, shouldBeElided } from "some-dep"; +export const bar = goodDeclaration<{}>; + + + +//// [index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.bar = void 0; +const some_dep_1 = require("some-dep"); +exports.bar = (some_dep_1.goodDeclaration); + + +//// [index.d.ts] +import { shouldReuseLocalName } from "some-dep"; +export declare const bar: () => () => { + shouldPrintResult: "N"; + shouldPrintResult2: "N"; + shouldLookupName: typeof import("some-dep").shouldLookupName; + shouldReuseLocalName: typeof shouldReuseLocalName; + reuseDepName: typeof import("some-dep").reuseDepName; +}; diff --git a/tests/baselines/reference/declarationEmitUsingTypeAlias2.symbols b/tests/baselines/reference/declarationEmitUsingTypeAlias2.symbols new file mode 100644 index 0000000000000..5a11bd9dcd2f0 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias2.symbols @@ -0,0 +1,87 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias2.ts] //// + +=== node_modules/some-dep/dist/inner.d.ts === +export declare type Other = { other: string }; +>Other : Symbol(Other, Decl(inner.d.ts, 0, 0)) +>other : Symbol(other, Decl(inner.d.ts, 0, 29)) + +export declare type SomeType = { arg: Other }; +>SomeType : Symbol(SomeType, Decl(inner.d.ts, 0, 46)) +>arg : Symbol(arg, Decl(inner.d.ts, 1, 32)) +>Other : Symbol(Other, Decl(inner.d.ts, 0, 0)) + +=== node_modules/some-dep/dist/other.d.ts === +export declare const shouldLookupName: unique symbol; +>shouldLookupName : Symbol(shouldLookupName, Decl(other.d.ts, 0, 20)) + +export declare const shouldReuseLocalName: unique symbol; +>shouldReuseLocalName : Symbol(shouldReuseLocalName, Decl(other.d.ts, 1, 20)) + +export declare const reuseDepName: unique symbol; +>reuseDepName : Symbol(reuseDepName, Decl(other.d.ts, 2, 20)) + +export declare const shouldBeElided: unique symbol; +>shouldBeElided : Symbol(shouldBeElided, Decl(other.d.ts, 3, 20)) + +export declare const isNotAccessibleShouldError: unique symbol; +>isNotAccessibleShouldError : Symbol(isNotAccessibleShouldError, Decl(other.d.ts, 4, 20)) + +=== node_modules/some-dep/dist/index.d.ts === +import { Other } from './inner' +>Other : Symbol(Other, Decl(index.d.ts, 0, 8)) + +import { shouldLookupName, reuseDepName, shouldReuseLocalName, shouldBeElided } from './other' +>shouldLookupName : Symbol(shouldLookupName, Decl(index.d.ts, 1, 8)) +>reuseDepName : Symbol(reuseDepName, Decl(index.d.ts, 1, 26)) +>shouldReuseLocalName : Symbol(shouldReuseLocalName, Decl(index.d.ts, 1, 40)) +>shouldBeElided : Symbol(shouldBeElided, Decl(index.d.ts, 1, 62)) + +export declare const goodDeclaration: () => () => { +>goodDeclaration : Symbol(goodDeclaration, Decl(index.d.ts, 2, 20)) +>T : Symbol(T, Decl(index.d.ts, 2, 39)) + + /** Other Can't be named in index.ts, but the whole conditional type can be resolved */ + shouldPrintResult: T extends Other? "O": "N", +>shouldPrintResult : Symbol(shouldPrintResult, Decl(index.d.ts, 2, 54)) +>T : Symbol(T, Decl(index.d.ts, 2, 39)) +>Other : Symbol(Other, Decl(index.d.ts, 0, 8)) + + /** Symbol shouldBeElided should not be present in index.d.ts, it might be since it's tracked before Other is seen and an error reported */ + shouldPrintResult2: T extends typeof shouldBeElided? Other: "N", +>shouldPrintResult2 : Symbol(shouldPrintResult2, Decl(index.d.ts, 4, 47)) +>T : Symbol(T, Decl(index.d.ts, 2, 39)) +>shouldBeElided : Symbol(shouldBeElided, Decl(index.d.ts, 1, 62)) +>Other : Symbol(Other, Decl(index.d.ts, 0, 8)) + + /** Specifier should come from module, local path should not be reused */ + shouldLookupName: typeof import('./other').shouldLookupName, +>shouldLookupName : Symbol(shouldLookupName, Decl(index.d.ts, 6, 66)) +>shouldLookupName : Symbol(shouldLookupName, Decl(other.d.ts, 0, 20)) + + /** This is imported in index so local name should be reused */ + shouldReuseLocalName: typeof shouldReuseLocalName +>shouldReuseLocalName : Symbol(shouldReuseLocalName, Decl(index.d.ts, 8, 62)) +>shouldReuseLocalName : Symbol(shouldReuseLocalName, Decl(index.d.ts, 1, 40)) + + /** This is NOT imported in index so import should be created */ + reuseDepName: typeof reuseDepName, +>reuseDepName : Symbol(reuseDepName, Decl(index.d.ts, 10, 51)) +>reuseDepName : Symbol(reuseDepName, Decl(index.d.ts, 1, 26)) +} +export { shouldLookupName, shouldReuseLocalName, reuseDepName, shouldBeElided }; +>shouldLookupName : Symbol(shouldLookupName, Decl(index.d.ts, 14, 8)) +>shouldReuseLocalName : Symbol(shouldReuseLocalName, Decl(index.d.ts, 14, 26)) +>reuseDepName : Symbol(reuseDepName, Decl(index.d.ts, 14, 48)) +>shouldBeElided : Symbol(shouldBeElided, Decl(index.d.ts, 14, 62)) + +=== src/index.ts === +import { goodDeclaration, shouldReuseLocalName, shouldBeElided } from "some-dep"; +>goodDeclaration : Symbol(goodDeclaration, Decl(index.ts, 0, 8)) +>shouldReuseLocalName : Symbol(shouldReuseLocalName, Decl(index.ts, 0, 25)) +>shouldBeElided : Symbol(shouldBeElided, Decl(index.ts, 0, 47)) + +export const bar = goodDeclaration<{}>; +>bar : Symbol(bar, Decl(index.ts, 1, 12)) +>goodDeclaration : Symbol(goodDeclaration, Decl(index.ts, 0, 8)) + + diff --git a/tests/baselines/reference/declarationEmitUsingTypeAlias2.types b/tests/baselines/reference/declarationEmitUsingTypeAlias2.types new file mode 100644 index 0000000000000..fec54d38ef751 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias2.types @@ -0,0 +1,115 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias2.ts] //// + +=== node_modules/some-dep/dist/inner.d.ts === +export declare type Other = { other: string }; +>Other : Other +> : ^^^^^ +>other : string +> : ^^^^^^ + +export declare type SomeType = { arg: Other }; +>SomeType : SomeType +> : ^^^^^^^^ +>arg : Other +> : ^^^^^ + +=== node_modules/some-dep/dist/other.d.ts === +export declare const shouldLookupName: unique symbol; +>shouldLookupName : unique symbol +> : ^^^^^^^^^^^^^ + +export declare const shouldReuseLocalName: unique symbol; +>shouldReuseLocalName : unique symbol +> : ^^^^^^^^^^^^^ + +export declare const reuseDepName: unique symbol; +>reuseDepName : unique symbol +> : ^^^^^^^^^^^^^ + +export declare const shouldBeElided: unique symbol; +>shouldBeElided : unique symbol +> : ^^^^^^^^^^^^^ + +export declare const isNotAccessibleShouldError: unique symbol; +>isNotAccessibleShouldError : unique symbol +> : ^^^^^^^^^^^^^ + +=== node_modules/some-dep/dist/index.d.ts === +import { Other } from './inner' +>Other : any +> : ^^^ + +import { shouldLookupName, reuseDepName, shouldReuseLocalName, shouldBeElided } from './other' +>shouldLookupName : unique symbol +> : ^^^^^^^^^^^^^ +>reuseDepName : unique symbol +> : ^^^^^^^^^^^^^ +>shouldReuseLocalName : unique symbol +> : ^^^^^^^^^^^^^ +>shouldBeElided : unique symbol +> : ^^^^^^^^^^^^^ + +export declare const goodDeclaration: () => () => { +>goodDeclaration : () => () => { shouldPrintResult: T extends Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? Other : "N"; shouldLookupName: typeof import("./other").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof reuseDepName; } +> : ^ ^^^^^^^ + + /** Other Can't be named in index.ts, but the whole conditional type can be resolved */ + shouldPrintResult: T extends Other? "O": "N", +>shouldPrintResult : T extends Other ? "O" : "N" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + /** Symbol shouldBeElided should not be present in index.d.ts, it might be since it's tracked before Other is seen and an error reported */ + shouldPrintResult2: T extends typeof shouldBeElided? Other: "N", +>shouldPrintResult2 : T extends unique symbol ? Other : "N" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>shouldBeElided : unique symbol +> : ^^^^^^^^^^^^^ + + /** Specifier should come from module, local path should not be reused */ + shouldLookupName: typeof import('./other').shouldLookupName, +>shouldLookupName : unique symbol +> : ^^^^^^^^^^^^^ +>shouldLookupName : error + + /** This is imported in index so local name should be reused */ + shouldReuseLocalName: typeof shouldReuseLocalName +>shouldReuseLocalName : unique symbol +> : ^^^^^^^^^^^^^ +>shouldReuseLocalName : unique symbol +> : ^^^^^^^^^^^^^ + + /** This is NOT imported in index so import should be created */ + reuseDepName: typeof reuseDepName, +>reuseDepName : unique symbol +> : ^^^^^^^^^^^^^ +>reuseDepName : unique symbol +> : ^^^^^^^^^^^^^ +} +export { shouldLookupName, shouldReuseLocalName, reuseDepName, shouldBeElided }; +>shouldLookupName : unique symbol +> : ^^^^^^^^^^^^^ +>shouldReuseLocalName : unique symbol +> : ^^^^^^^^^^^^^ +>reuseDepName : unique symbol +> : ^^^^^^^^^^^^^ +>shouldBeElided : unique symbol +> : ^^^^^^^^^^^^^ + +=== src/index.ts === +import { goodDeclaration, shouldReuseLocalName, shouldBeElided } from "some-dep"; +>goodDeclaration : () => () => { shouldPrintResult: T extends import("node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("node_modules/some-dep/dist/other").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("node_modules/some-dep/dist/other").reuseDepName; } +> : ^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ +>shouldReuseLocalName : unique symbol +> : ^^^^^^^^^^^^^ +>shouldBeElided : unique symbol +> : ^^^^^^^^^^^^^ + +export const bar = goodDeclaration<{}>; +>bar : () => () => { shouldPrintResult: {} extends import("node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: {} extends typeof shouldBeElided ? import("node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("node_modules/some-dep/dist/other").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("node_modules/some-dep/dist/other").reuseDepName; } +> : ^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ +>goodDeclaration<{}> : () => () => { shouldPrintResult: {} extends import("node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: {} extends typeof shouldBeElided ? import("node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("node_modules/some-dep/dist/other").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("node_modules/some-dep/dist/other").reuseDepName; } +> : ^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ +>goodDeclaration : () => () => { shouldPrintResult: T extends import("node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("node_modules/some-dep/dist/other").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("node_modules/some-dep/dist/other").reuseDepName; } +> : ^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ + + diff --git a/tests/cases/compiler/declarationEmitUsingTypeAlias2.ts b/tests/cases/compiler/declarationEmitUsingTypeAlias2.ts new file mode 100644 index 0000000000000..f1f106d5001ba --- /dev/null +++ b/tests/cases/compiler/declarationEmitUsingTypeAlias2.ts @@ -0,0 +1,44 @@ +// @strict: true +// @declaration: true +// @module: nodenext + +// @filename: node_modules/some-dep/dist/inner.d.ts +export declare type Other = { other: string }; +export declare type SomeType = { arg: Other }; + +// @filename: node_modules/some-dep/dist/other.d.ts +export declare const shouldLookupName: unique symbol; +export declare const shouldReuseLocalName: unique symbol; +export declare const reuseDepName: unique symbol; +export declare const shouldBeElided: unique symbol; +export declare const isNotAccessibleShouldError: unique symbol; + +// @filename: node_modules/some-dep/dist/index.d.ts +import { Other } from './inner' +import { shouldLookupName, reuseDepName, shouldReuseLocalName, shouldBeElided } from './other' +export declare const goodDeclaration: () => () => { + /** Other Can't be named in index.ts, but the whole conditional type can be resolved */ + shouldPrintResult: T extends Other? "O": "N", + /** Symbol shouldBeElided should not be present in index.d.ts, it might be since it's tracked before Other is seen and an error reported */ + shouldPrintResult2: T extends typeof shouldBeElided? Other: "N", + /** Specifier should come from module, local path should not be reused */ + shouldLookupName: typeof import('./other').shouldLookupName, + /** This is imported in index so local name should be reused */ + shouldReuseLocalName: typeof shouldReuseLocalName + /** This is NOT imported in index so import should be created */ + reuseDepName: typeof reuseDepName, +} +export { shouldLookupName, shouldReuseLocalName, reuseDepName, shouldBeElided }; + +// @filename: node_modules/some-dep/package.json +{ + "name": "some-dep", + "exports": { + ".": "./dist/index.js" + } +} + +// @filename: src/index.ts +import { goodDeclaration, shouldReuseLocalName, shouldBeElided } from "some-dep"; +export const bar = goodDeclaration<{}>; +