diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d9823a350a1..bf1ed0b1206 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8415,7 +8415,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeFromTypeNode === type) { return true; } - if (annotatedDeclaration && (isParameter(annotatedDeclaration) || isPropertySignature(annotatedDeclaration) || isPropertyDeclaration(annotatedDeclaration)) && annotatedDeclaration.questionToken) { + if (!annotatedDeclaration) { + return false; + } + if ((isPropertySignature(annotatedDeclaration) || isPropertyDeclaration(annotatedDeclaration)) && annotatedDeclaration.questionToken) { + return getTypeWithFacts(type, TypeFacts.NEUndefined) === typeFromTypeNode; + } + if (isParameter(annotatedDeclaration) && hasEffectiveQuestionToken(annotatedDeclaration)) { return getTypeWithFacts(type, TypeFacts.NEUndefined) === typeFromTypeNode; } return false; @@ -9420,7 +9426,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const skipMembershipCheck = !isPrivate; // We only call this on exported symbols when we know they're in the correct scope if (skipMembershipCheck || (!!length(symbol.declarations) && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration)))) { const scopeCleanup = cloneNodeBuilderContext(context); + context.tracker.pushErrorFallbackNode(find(symbol.declarations, d => getSourceFileOfNode(d) === context.enclosingFile)); serializeSymbolWorker(symbol, isPrivate, propertyAsAlias); + context.tracker.popErrorFallbackNode(); scopeCleanup(); } } @@ -53022,4 +53030,12 @@ class SymbolTrackerImpl implements SymbolTracker { this.inner.reportInferenceFallback(node); } } + + pushErrorFallbackNode(node: Declaration | undefined): void { + return this.inner?.pushErrorFallbackNode?.(node); + } + + popErrorFallbackNode(): void { + return this.inner?.popErrorFallbackNode?.(); + } } diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index fa04121f7cc..a5475cf1562 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -270,6 +270,7 @@ export function transformDeclarations(context: TransformationContext): Transform const { factory } = context; const host = context.getEmitHost(); + let restoreFallbackNode = () => void 0; const symbolTracker: SymbolTracker = { trackSymbol, reportInaccessibleThisError, @@ -282,6 +283,18 @@ export function transformDeclarations(context: TransformationContext): Transform reportNonlocalAugmentation, reportNonSerializableProperty, reportInferenceFallback, + pushErrorFallbackNode(node) { + const currentFallback = errorFallbackNode; + const currentRestore = restoreFallbackNode; + restoreFallbackNode = () => { + restoreFallbackNode = currentRestore; + errorFallbackNode = currentFallback; + }; + errorFallbackNode = node; + }, + popErrorFallbackNode() { + restoreFallbackNode(); + }, }; let errorNameNode: DeclarationName | undefined; let errorFallbackNode: Declaration | undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 93cd88ef2a3..0d3e7ebfbe1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -9958,6 +9958,8 @@ export interface SymbolTracker { reportNonlocalAugmentation?(containingFile: SourceFile, parentSymbol: Symbol, augmentingSymbol: Symbol): void; reportNonSerializableProperty?(propertyName: string): void; reportInferenceFallback?(node: Node): void; + pushErrorFallbackNode?(node: Declaration | undefined): void; + popErrorFallbackNode?(): void; } export interface TextSpan { diff --git a/tests/baselines/reference/contextuallyTypedParametersOptionalInJSDoc.types b/tests/baselines/reference/contextuallyTypedParametersOptionalInJSDoc.types index 8160cf486a3..3bcd3542cdf 100644 --- a/tests/baselines/reference/contextuallyTypedParametersOptionalInJSDoc.types +++ b/tests/baselines/reference/contextuallyTypedParametersOptionalInJSDoc.types @@ -70,10 +70,10 @@ const fn2 = * @param {number} [b] */ function self(a, b) { ->function self(a, b) { acceptNum(b); // error self(""); self("", undefined); } : (a: string, b?: number | undefined) => void -> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->self : (a: string, b?: number | undefined) => void -> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>function self(a, b) { acceptNum(b); // error self(""); self("", undefined); } : (a: string, b?: number) => void +> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^ +>self : (a: string, b?: number) => void +> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^ >a : string > : ^^^^^^ >b : number | undefined @@ -90,16 +90,16 @@ const fn2 = self(""); >self("") : void > : ^^^^ ->self : (a: string, b?: number | undefined) => void -> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>self : (a: string, b?: number) => void +> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^ >"" : "" > : ^^ self("", undefined); >self("", undefined) : void > : ^^^^ ->self : (a: string, b?: number | undefined) => void -> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>self : (a: string, b?: number) => void +> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^ >"" : "" > : ^^ >undefined : undefined diff --git a/tests/baselines/reference/contravariantOnlyInferenceWithAnnotatedOptionalParameterJs.types b/tests/baselines/reference/contravariantOnlyInferenceWithAnnotatedOptionalParameterJs.types index a6a181075b9..852b6aee63f 100644 --- a/tests/baselines/reference/contravariantOnlyInferenceWithAnnotatedOptionalParameterJs.types +++ b/tests/baselines/reference/contravariantOnlyInferenceWithAnnotatedOptionalParameterJs.types @@ -28,8 +28,8 @@ const a = filter( * @param {number} [pose] */ (pose) => true ->(pose) => true : (pose?: number | undefined) => true -> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(pose) => true : (pose?: number) => true +> : ^ ^^^ ^^^^^^^^^ >pose : number | undefined > : ^^^^^^^^^^^^^^^^^^ >true : true @@ -50,8 +50,8 @@ const b = filter( * @param {number} [_] */ (pose, _) => true ->(pose, _) => true : (pose?: number | undefined, _?: number | undefined) => true -> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(pose, _) => true : (pose?: number, _?: number) => true +> : ^ ^^^ ^^ ^^^ ^^^^^^^^^ >pose : number | undefined > : ^^^^^^^^^^^^^^^^^^ >_ : number | undefined diff --git a/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.js b/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.js new file mode 100644 index 00000000000..e33afbfb1ce --- /dev/null +++ b/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.js @@ -0,0 +1,63 @@ +//// [tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts] //// + +//// [package.json] +{ + "name": "typescript-issue", + "private": true, + "version": "0.0.0", + "type": "module" +} +//// [package.json] +{ + "name": "@lion/ajax", + "version": "2.0.2", + "type": "module", + "exports": { + ".": { + "types": "./dist-types/src/index.d.ts", + "default": "./src/index.js" + }, + "./docs/*": "./docs/*" + } +} +//// [index.d.ts] +export type LionRequestInit = import('../types/types.js').LionRequestInit; +//// [types.d.ts] +export interface LionRequestInit { + body?: null | Object; +} +//// [index.js] +/** + * @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit + */ + +export class NewAjax { + /** + * @param {LionRequestInit} [init] + */ + case5_unexpectedlyResolvesPathToNodeModules(init) {} +} + +/** + * @type {(init?: LionRequestInit) => void} + */ +// @ts-expect-error +NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules; + + + +//// [index.d.ts] +/** + * @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit + */ +export class NewAjax { + /** + * @param {LionRequestInit} [init] + */ + case5_unexpectedlyResolvesPathToNodeModules(init?: LionRequestInit): void; + /** + * @type {(init?: LionRequestInit) => void} + */ + case6_unexpectedlyResolvesPathToNodeModules: (init?: LionRequestInit) => void; +} +export type LionRequestInit = import("@lion/ajax").LionRequestInit; diff --git a/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.symbols b/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.symbols new file mode 100644 index 00000000000..b501d1c1773 --- /dev/null +++ b/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.symbols @@ -0,0 +1,42 @@ +//// [tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts] //// + +=== node_modules/@lion/ajax/dist-types/src/index.d.ts === +export type LionRequestInit = import('../types/types.js').LionRequestInit; +>LionRequestInit : Symbol(LionRequestInit, Decl(index.d.ts, 0, 0)) +>LionRequestInit : Symbol(LionRequestInit, Decl(types.d.ts, 0, 0)) + +=== node_modules/@lion/ajax/dist-types/types/types.d.ts === +export interface LionRequestInit { +>LionRequestInit : Symbol(LionRequestInit, Decl(types.d.ts, 0, 0)) + + body?: null | Object; +>body : Symbol(LionRequestInit.body, Decl(types.d.ts, 0, 34)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} +=== index.js === +/** + * @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit + */ + +export class NewAjax { +>NewAjax : Symbol(NewAjax, Decl(index.js, 0, 0)) + + /** + * @param {LionRequestInit} [init] + */ + case5_unexpectedlyResolvesPathToNodeModules(init) {} +>case5_unexpectedlyResolvesPathToNodeModules : Symbol(NewAjax.case5_unexpectedlyResolvesPathToNodeModules, Decl(index.js, 4, 22)) +>init : Symbol(init, Decl(index.js, 8, 48)) +} + +/** + * @type {(init?: LionRequestInit) => void} + */ +// @ts-expect-error +NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules; +>NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules : Symbol(NewAjax.case6_unexpectedlyResolvesPathToNodeModules, Decl(index.js, 9, 1)) +>NewAjax.prototype : Symbol(NewAjax.prototype) +>NewAjax : Symbol(NewAjax, Decl(index.js, 0, 0)) +>prototype : Symbol(NewAjax.prototype) +>case6_unexpectedlyResolvesPathToNodeModules : Symbol(NewAjax.case6_unexpectedlyResolvesPathToNodeModules, Decl(index.js, 9, 1)) + diff --git a/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.types b/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.types new file mode 100644 index 00000000000..b16125c51e4 --- /dev/null +++ b/tests/baselines/reference/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.types @@ -0,0 +1,48 @@ +//// [tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts] //// + +=== node_modules/@lion/ajax/dist-types/src/index.d.ts === +export type LionRequestInit = import('../types/types.js').LionRequestInit; +>LionRequestInit : import("node_modules/@lion/ajax/dist-types/types/types").LionRequestInit +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +=== node_modules/@lion/ajax/dist-types/types/types.d.ts === +export interface LionRequestInit { + body?: null | Object; +>body : Object | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +} +=== index.js === +/** + * @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit + */ + +export class NewAjax { +>NewAjax : NewAjax +> : ^^^^^^^ + + /** + * @param {LionRequestInit} [init] + */ + case5_unexpectedlyResolvesPathToNodeModules(init) {} +>case5_unexpectedlyResolvesPathToNodeModules : (init?: LionRequestInit) => void +> : ^ ^^^ ^^^^^^^^^ +>init : import("node_modules/@lion/ajax/dist-types/types/types").LionRequestInit | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +/** + * @type {(init?: LionRequestInit) => void} + */ +// @ts-expect-error +NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules; +>NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules : (init?: LionRequestInit) => void +> : ^ ^^^ ^^^^^ +>NewAjax.prototype : NewAjax +> : ^^^^^^^ +>NewAjax : typeof NewAjax +> : ^^^^^^^^^^^^^^ +>prototype : NewAjax +> : ^^^^^^^ +>case6_unexpectedlyResolvesPathToNodeModules : (init?: LionRequestInit) => void +> : ^ ^^^ ^^^^^ + diff --git a/tests/baselines/reference/paramTagBracketsAddOptionalUndefined.types b/tests/baselines/reference/paramTagBracketsAddOptionalUndefined.types index b47f13a4e48..be5e4799e06 100644 --- a/tests/baselines/reference/paramTagBracketsAddOptionalUndefined.types +++ b/tests/baselines/reference/paramTagBracketsAddOptionalUndefined.types @@ -7,8 +7,8 @@ * @param {number} [r=101] */ function f(p, q, r) { ->f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void -> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f : (p?: number, q?: number | undefined, r?: number) => void +> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^ >p : number | undefined > : ^^^^^^^^^^^^^^^^^^ >q : number | undefined @@ -45,14 +45,14 @@ function f(p, q, r) { f() >f() : void > : ^^^^ ->f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void -> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f : (p?: number, q?: number | undefined, r?: number) => void +> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^ f(undefined, undefined, undefined) >f(undefined, undefined, undefined) : void > : ^^^^ ->f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void -> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f : (p?: number, q?: number | undefined, r?: number) => void +> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^ >undefined : undefined > : ^^^^^^^^^ >undefined : undefined @@ -63,8 +63,8 @@ f(undefined, undefined, undefined) f(1, 2, 3) >f(1, 2, 3) : void > : ^^^^ ->f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void -> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f : (p?: number, q?: number | undefined, r?: number) => void +> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^ >1 : 1 > : ^ >2 : 2 diff --git a/tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts b/tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts new file mode 100644 index 00000000000..5b01371a461 --- /dev/null +++ b/tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts @@ -0,0 +1,52 @@ +// @allowJs: true +// @checkJs: true +// @strict: true +// @target: esnext +// @module: nodenext +// @moduleResolution: nodenext +// @declaration: true +// @emitDeclarationOnly: true +// @outDir: ./dist-types +// @filename: package.json +{ + "name": "typescript-issue", + "private": true, + "version": "0.0.0", + "type": "module" +} +// @filename: node_modules/@lion/ajax/package.json +{ + "name": "@lion/ajax", + "version": "2.0.2", + "type": "module", + "exports": { + ".": { + "types": "./dist-types/src/index.d.ts", + "default": "./src/index.js" + }, + "./docs/*": "./docs/*" + } +} +// @filename: node_modules/@lion/ajax/dist-types/src/index.d.ts +export type LionRequestInit = import('../types/types.js').LionRequestInit; +// @filename: node_modules/@lion/ajax/dist-types/types/types.d.ts +export interface LionRequestInit { + body?: null | Object; +} +// @filename: index.js +/** + * @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit + */ + +export class NewAjax { + /** + * @param {LionRequestInit} [init] + */ + case5_unexpectedlyResolvesPathToNodeModules(init) {} +} + +/** + * @type {(init?: LionRequestInit) => void} + */ +// @ts-expect-error +NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules; \ No newline at end of file