Skip to content

Commit 3ad0f75

Browse files
authored
Fix occasional silent error emit for JSDoc declaration emit and overzealous node serialization of jsdoc optional parameters. (#60034)
1 parent 8496039 commit 3ad0f75

10 files changed

+257
-21
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8415,7 +8415,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
84158415
if (typeFromTypeNode === type) {
84168416
return true;
84178417
}
8418-
if (annotatedDeclaration && (isParameter(annotatedDeclaration) || isPropertySignature(annotatedDeclaration) || isPropertyDeclaration(annotatedDeclaration)) && annotatedDeclaration.questionToken) {
8418+
if (!annotatedDeclaration) {
8419+
return false;
8420+
}
8421+
if ((isPropertySignature(annotatedDeclaration) || isPropertyDeclaration(annotatedDeclaration)) && annotatedDeclaration.questionToken) {
8422+
return getTypeWithFacts(type, TypeFacts.NEUndefined) === typeFromTypeNode;
8423+
}
8424+
if (isParameter(annotatedDeclaration) && hasEffectiveQuestionToken(annotatedDeclaration)) {
84198425
return getTypeWithFacts(type, TypeFacts.NEUndefined) === typeFromTypeNode;
84208426
}
84218427
return false;
@@ -9420,7 +9426,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
94209426
const skipMembershipCheck = !isPrivate; // We only call this on exported symbols when we know they're in the correct scope
94219427
if (skipMembershipCheck || (!!length(symbol.declarations) && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration)))) {
94229428
const scopeCleanup = cloneNodeBuilderContext(context);
9429+
context.tracker.pushErrorFallbackNode(find(symbol.declarations, d => getSourceFileOfNode(d) === context.enclosingFile));
94239430
serializeSymbolWorker(symbol, isPrivate, propertyAsAlias);
9431+
context.tracker.popErrorFallbackNode();
94249432
scopeCleanup();
94259433
}
94269434
}
@@ -53022,4 +53030,12 @@ class SymbolTrackerImpl implements SymbolTracker {
5302253030
this.inner.reportInferenceFallback(node);
5302353031
}
5302453032
}
53033+
53034+
pushErrorFallbackNode(node: Declaration | undefined): void {
53035+
return this.inner?.pushErrorFallbackNode?.(node);
53036+
}
53037+
53038+
popErrorFallbackNode(): void {
53039+
return this.inner?.popErrorFallbackNode?.();
53040+
}
5302553041
}

src/compiler/transformers/declarations.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ export function transformDeclarations(context: TransformationContext): Transform
270270

271271
const { factory } = context;
272272
const host = context.getEmitHost();
273+
let restoreFallbackNode = () => void 0;
273274
const symbolTracker: SymbolTracker = {
274275
trackSymbol,
275276
reportInaccessibleThisError,
@@ -282,6 +283,18 @@ export function transformDeclarations(context: TransformationContext): Transform
282283
reportNonlocalAugmentation,
283284
reportNonSerializableProperty,
284285
reportInferenceFallback,
286+
pushErrorFallbackNode(node) {
287+
const currentFallback = errorFallbackNode;
288+
const currentRestore = restoreFallbackNode;
289+
restoreFallbackNode = () => {
290+
restoreFallbackNode = currentRestore;
291+
errorFallbackNode = currentFallback;
292+
};
293+
errorFallbackNode = node;
294+
},
295+
popErrorFallbackNode() {
296+
restoreFallbackNode();
297+
},
285298
};
286299
let errorNameNode: DeclarationName | undefined;
287300
let errorFallbackNode: Declaration | undefined;

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9958,6 +9958,8 @@ export interface SymbolTracker {
99589958
reportNonlocalAugmentation?(containingFile: SourceFile, parentSymbol: Symbol, augmentingSymbol: Symbol): void;
99599959
reportNonSerializableProperty?(propertyName: string): void;
99609960
reportInferenceFallback?(node: Node): void;
9961+
pushErrorFallbackNode?(node: Declaration | undefined): void;
9962+
popErrorFallbackNode?(): void;
99619963
}
99629964

99639965
export interface TextSpan {

tests/baselines/reference/contextuallyTypedParametersOptionalInJSDoc.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ const fn2 =
7070
* @param {number} [b]
7171
*/
7272
function self(a, b) {
73-
>function self(a, b) { acceptNum(b); // error self(""); self("", undefined); } : (a: string, b?: number | undefined) => void
74-
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75-
>self : (a: string, b?: number | undefined) => void
76-
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
73+
>function self(a, b) { acceptNum(b); // error self(""); self("", undefined); } : (a: string, b?: number) => void
74+
> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
75+
>self : (a: string, b?: number) => void
76+
> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
7777
>a : string
7878
> : ^^^^^^
7979
>b : number | undefined
@@ -90,16 +90,16 @@ const fn2 =
9090
self("");
9191
>self("") : void
9292
> : ^^^^
93-
>self : (a: string, b?: number | undefined) => void
94-
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
93+
>self : (a: string, b?: number) => void
94+
> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
9595
>"" : ""
9696
> : ^^
9797

9898
self("", undefined);
9999
>self("", undefined) : void
100100
> : ^^^^
101-
>self : (a: string, b?: number | undefined) => void
102-
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
101+
>self : (a: string, b?: number) => void
102+
> : ^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
103103
>"" : ""
104104
> : ^^
105105
>undefined : undefined

tests/baselines/reference/contravariantOnlyInferenceWithAnnotatedOptionalParameterJs.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ const a = filter(
2828
* @param {number} [pose]
2929
*/
3030
(pose) => true
31-
>(pose) => true : (pose?: number | undefined) => true
32-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
>(pose) => true : (pose?: number) => true
32+
> : ^ ^^^ ^^^^^^^^^
3333
>pose : number | undefined
3434
> : ^^^^^^^^^^^^^^^^^^
3535
>true : true
@@ -50,8 +50,8 @@ const b = filter(
5050
* @param {number} [_]
5151
*/
5252
(pose, _) => true
53-
>(pose, _) => true : (pose?: number | undefined, _?: number | undefined) => true
54-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
53+
>(pose, _) => true : (pose?: number, _?: number) => true
54+
> : ^ ^^^ ^^ ^^^ ^^^^^^^^^
5555
>pose : number | undefined
5656
> : ^^^^^^^^^^^^^^^^^^
5757
>_ : number | undefined
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//// [tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts] ////
2+
3+
//// [package.json]
4+
{
5+
"name": "typescript-issue",
6+
"private": true,
7+
"version": "0.0.0",
8+
"type": "module"
9+
}
10+
//// [package.json]
11+
{
12+
"name": "@lion/ajax",
13+
"version": "2.0.2",
14+
"type": "module",
15+
"exports": {
16+
".": {
17+
"types": "./dist-types/src/index.d.ts",
18+
"default": "./src/index.js"
19+
},
20+
"./docs/*": "./docs/*"
21+
}
22+
}
23+
//// [index.d.ts]
24+
export type LionRequestInit = import('../types/types.js').LionRequestInit;
25+
//// [types.d.ts]
26+
export interface LionRequestInit {
27+
body?: null | Object;
28+
}
29+
//// [index.js]
30+
/**
31+
* @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit
32+
*/
33+
34+
export class NewAjax {
35+
/**
36+
* @param {LionRequestInit} [init]
37+
*/
38+
case5_unexpectedlyResolvesPathToNodeModules(init) {}
39+
}
40+
41+
/**
42+
* @type {(init?: LionRequestInit) => void}
43+
*/
44+
// @ts-expect-error
45+
NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules;
46+
47+
48+
49+
//// [index.d.ts]
50+
/**
51+
* @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit
52+
*/
53+
export class NewAjax {
54+
/**
55+
* @param {LionRequestInit} [init]
56+
*/
57+
case5_unexpectedlyResolvesPathToNodeModules(init?: LionRequestInit): void;
58+
/**
59+
* @type {(init?: LionRequestInit) => void}
60+
*/
61+
case6_unexpectedlyResolvesPathToNodeModules: (init?: LionRequestInit) => void;
62+
}
63+
export type LionRequestInit = import("@lion/ajax").LionRequestInit;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts] ////
2+
3+
=== node_modules/@lion/ajax/dist-types/src/index.d.ts ===
4+
export type LionRequestInit = import('../types/types.js').LionRequestInit;
5+
>LionRequestInit : Symbol(LionRequestInit, Decl(index.d.ts, 0, 0))
6+
>LionRequestInit : Symbol(LionRequestInit, Decl(types.d.ts, 0, 0))
7+
8+
=== node_modules/@lion/ajax/dist-types/types/types.d.ts ===
9+
export interface LionRequestInit {
10+
>LionRequestInit : Symbol(LionRequestInit, Decl(types.d.ts, 0, 0))
11+
12+
body?: null | Object;
13+
>body : Symbol(LionRequestInit.body, Decl(types.d.ts, 0, 34))
14+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
15+
}
16+
=== index.js ===
17+
/**
18+
* @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit
19+
*/
20+
21+
export class NewAjax {
22+
>NewAjax : Symbol(NewAjax, Decl(index.js, 0, 0))
23+
24+
/**
25+
* @param {LionRequestInit} [init]
26+
*/
27+
case5_unexpectedlyResolvesPathToNodeModules(init) {}
28+
>case5_unexpectedlyResolvesPathToNodeModules : Symbol(NewAjax.case5_unexpectedlyResolvesPathToNodeModules, Decl(index.js, 4, 22))
29+
>init : Symbol(init, Decl(index.js, 8, 48))
30+
}
31+
32+
/**
33+
* @type {(init?: LionRequestInit) => void}
34+
*/
35+
// @ts-expect-error
36+
NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules;
37+
>NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules : Symbol(NewAjax.case6_unexpectedlyResolvesPathToNodeModules, Decl(index.js, 9, 1))
38+
>NewAjax.prototype : Symbol(NewAjax.prototype)
39+
>NewAjax : Symbol(NewAjax, Decl(index.js, 0, 0))
40+
>prototype : Symbol(NewAjax.prototype)
41+
>case6_unexpectedlyResolvesPathToNodeModules : Symbol(NewAjax.case6_unexpectedlyResolvesPathToNodeModules, Decl(index.js, 9, 1))
42+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//// [tests/cases/compiler/jsDocDeclarationEmitDoesNotUseNodeModulesPathWithoutError.ts] ////
2+
3+
=== node_modules/@lion/ajax/dist-types/src/index.d.ts ===
4+
export type LionRequestInit = import('../types/types.js').LionRequestInit;
5+
>LionRequestInit : import("node_modules/@lion/ajax/dist-types/types/types").LionRequestInit
6+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7+
8+
=== node_modules/@lion/ajax/dist-types/types/types.d.ts ===
9+
export interface LionRequestInit {
10+
body?: null | Object;
11+
>body : Object | null | undefined
12+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
13+
}
14+
=== index.js ===
15+
/**
16+
* @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit
17+
*/
18+
19+
export class NewAjax {
20+
>NewAjax : NewAjax
21+
> : ^^^^^^^
22+
23+
/**
24+
* @param {LionRequestInit} [init]
25+
*/
26+
case5_unexpectedlyResolvesPathToNodeModules(init) {}
27+
>case5_unexpectedlyResolvesPathToNodeModules : (init?: LionRequestInit) => void
28+
> : ^ ^^^ ^^^^^^^^^
29+
>init : import("node_modules/@lion/ajax/dist-types/types/types").LionRequestInit | undefined
30+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
}
32+
33+
/**
34+
* @type {(init?: LionRequestInit) => void}
35+
*/
36+
// @ts-expect-error
37+
NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules;
38+
>NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules : (init?: LionRequestInit) => void
39+
> : ^ ^^^ ^^^^^
40+
>NewAjax.prototype : NewAjax
41+
> : ^^^^^^^
42+
>NewAjax : typeof NewAjax
43+
> : ^^^^^^^^^^^^^^
44+
>prototype : NewAjax
45+
> : ^^^^^^^
46+
>case6_unexpectedlyResolvesPathToNodeModules : (init?: LionRequestInit) => void
47+
> : ^ ^^^ ^^^^^
48+

tests/baselines/reference/paramTagBracketsAddOptionalUndefined.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
* @param {number} [r=101]
88
*/
99
function f(p, q, r) {
10-
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
11-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10+
>f : (p?: number, q?: number | undefined, r?: number) => void
11+
> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^
1212
>p : number | undefined
1313
> : ^^^^^^^^^^^^^^^^^^
1414
>q : number | undefined
@@ -45,14 +45,14 @@ function f(p, q, r) {
4545
f()
4646
>f() : void
4747
> : ^^^^
48-
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
49-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
>f : (p?: number, q?: number | undefined, r?: number) => void
49+
> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^
5050

5151
f(undefined, undefined, undefined)
5252
>f(undefined, undefined, undefined) : void
5353
> : ^^^^
54-
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
55-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54+
>f : (p?: number, q?: number | undefined, r?: number) => void
55+
> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^
5656
>undefined : undefined
5757
> : ^^^^^^^^^
5858
>undefined : undefined
@@ -63,8 +63,8 @@ f(undefined, undefined, undefined)
6363
f(1, 2, 3)
6464
>f(1, 2, 3) : void
6565
> : ^^^^
66-
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
67-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66+
>f : (p?: number, q?: number | undefined, r?: number) => void
67+
> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^ ^^^ ^^^^^^^^^
6868
>1 : 1
6969
> : ^
7070
>2 : 2
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @strict: true
4+
// @target: esnext
5+
// @module: nodenext
6+
// @moduleResolution: nodenext
7+
// @declaration: true
8+
// @emitDeclarationOnly: true
9+
// @outDir: ./dist-types
10+
// @filename: package.json
11+
{
12+
"name": "typescript-issue",
13+
"private": true,
14+
"version": "0.0.0",
15+
"type": "module"
16+
}
17+
// @filename: node_modules/@lion/ajax/package.json
18+
{
19+
"name": "@lion/ajax",
20+
"version": "2.0.2",
21+
"type": "module",
22+
"exports": {
23+
".": {
24+
"types": "./dist-types/src/index.d.ts",
25+
"default": "./src/index.js"
26+
},
27+
"./docs/*": "./docs/*"
28+
}
29+
}
30+
// @filename: node_modules/@lion/ajax/dist-types/src/index.d.ts
31+
export type LionRequestInit = import('../types/types.js').LionRequestInit;
32+
// @filename: node_modules/@lion/ajax/dist-types/types/types.d.ts
33+
export interface LionRequestInit {
34+
body?: null | Object;
35+
}
36+
// @filename: index.js
37+
/**
38+
* @typedef {import('@lion/ajax').LionRequestInit} LionRequestInit
39+
*/
40+
41+
export class NewAjax {
42+
/**
43+
* @param {LionRequestInit} [init]
44+
*/
45+
case5_unexpectedlyResolvesPathToNodeModules(init) {}
46+
}
47+
48+
/**
49+
* @type {(init?: LionRequestInit) => void}
50+
*/
51+
// @ts-expect-error
52+
NewAjax.prototype.case6_unexpectedlyResolvesPathToNodeModules;

0 commit comments

Comments
 (0)