Skip to content

Commit 7b70f43

Browse files
committed
Fix 'as const'-like behavior in JSDoc type cast
1 parent d50c91d commit 7b70f43

File tree

8 files changed

+66
-7
lines changed

8 files changed

+66
-7
lines changed

src/compiler/checker.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -25858,7 +25858,9 @@ namespace ts {
2585825858
case SyntaxKind.ParenthesizedExpression: {
2585925859
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
2586025860
const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined;
25861-
return tag ? getTypeFromTypeNode(tag.typeExpression.type) : getContextualType(parent as ParenthesizedExpression, contextFlags);
25861+
return !tag ? getContextualType(parent as ParenthesizedExpression, contextFlags) :
25862+
isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? tryFindWhenConstTypeReference(parent as ParenthesizedExpression) :
25863+
getTypeFromTypeNode(tag.typeExpression.type);
2586225864
}
2586325865
case SyntaxKind.NonNullExpression:
2586425866
return getContextualType(parent as NonNullExpression, contextFlags);

src/compiler/utilities.ts

+22-2
Original file line numberDiff line numberDiff line change
@@ -2634,13 +2634,13 @@ namespace ts {
26342634
let result: (JSDoc | JSDocTag)[] | undefined;
26352635
// Pull parameter comments from declaring function as well
26362636
if (isVariableLike(hostNode) && hasInitializer(hostNode) && hasJSDocNodes(hostNode.initializer!)) {
2637-
result = append(result, last((hostNode.initializer as HasJSDoc).jsDoc!));
2637+
result = addRange(result, filterOwnedJSDocTags(hostNode, last((hostNode.initializer as HasJSDoc).jsDoc!)));
26382638
}
26392639

26402640
let node: Node | undefined = hostNode;
26412641
while (node && node.parent) {
26422642
if (hasJSDocNodes(node)) {
2643-
result = append(result, last(node.jsDoc!));
2643+
result = addRange(result, filterOwnedJSDocTags(hostNode, last(node.jsDoc!)));
26442644
}
26452645

26462646
if (node.kind === SyntaxKind.Parameter) {
@@ -2656,6 +2656,26 @@ namespace ts {
26562656
return result || emptyArray;
26572657
}
26582658

2659+
function filterOwnedJSDocTags(hostNode: Node, jsDoc: JSDoc | JSDocTag) {
2660+
if (isJSDoc(jsDoc)) {
2661+
const ownedTags = filter(jsDoc.tags, tag => ownsJSDocTag(hostNode, tag));
2662+
return jsDoc.tags === ownedTags ? [jsDoc] : ownedTags;
2663+
}
2664+
return ownsJSDocTag(hostNode, jsDoc) ? [jsDoc] : undefined;
2665+
}
2666+
2667+
/**
2668+
* Determines whether a host node owns a jsDoc tag. A `@type` tag attached to a
2669+
* a ParenthesizedExpression belongs only to the ParenthesizedExpression.
2670+
*/
2671+
function ownsJSDocTag(hostNode: Node, tag: JSDocTag) {
2672+
return !isJSDocTypeTag(tag)
2673+
|| !tag.parent
2674+
|| !isJSDoc(tag.parent)
2675+
|| !isParenthesizedExpression(tag.parent.parent)
2676+
|| tag.parent.parent === hostNode;
2677+
}
2678+
26592679
export function getNextJSDocCommentLocation(node: Node) {
26602680
const parent = node.parent;
26612681
if (parent.kind === SyntaxKind.PropertyAssignment ||

tests/baselines/reference/importTypeInJSDoc.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ export = MyClass;
3737
*/
3838

3939
let a = /** @type {Foo} */(/** @type {*} */(undefined));
40-
>a : import("tests/cases/conformance/types/import/externs")
40+
>a : any
4141
>(/** @type {*} */(undefined)) : import("tests/cases/conformance/types/import/externs")
4242
>(undefined) : any
4343
>undefined : undefined
4444

4545
a = new Foo({doer: Foo.Bar});
4646
>a = new Foo({doer: Foo.Bar}) : import("tests/cases/conformance/types/import/externs")
47-
>a : import("tests/cases/conformance/types/import/externs")
47+
>a : any
4848
>new Foo({doer: Foo.Bar}) : import("tests/cases/conformance/types/import/externs")
4949
>Foo : typeof import("tests/cases/conformance/types/import/externs")
5050
>{doer: Foo.Bar} : { doer: (x: string, y?: number) => void; }

tests/baselines/reference/jsdocTypeTagCast.errors.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,7 @@ tests/cases/conformance/jsdoc/b.js(67,8): error TS2454: Variable 'numOrStr' is u
123123
}
124124

125125

126-
126+
var asConst1 = /** @type {const} */(1);
127+
var asConst2 = /** @type {const} */({
128+
x: 1
129+
});

tests/baselines/reference/jsdocTypeTagCast.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
7474
}
7575

7676

77-
77+
var asConst1 = /** @type {const} */(1);
78+
var asConst2 = /** @type {const} */({
79+
x: 1
80+
});
7881

7982
//// [a.js]
8083
var W;
@@ -154,3 +157,7 @@ var str;
154157
if ( /** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
155158
str = numOrStr; // Error, no narrowing occurred
156159
}
160+
var asConst1 = /** @type {const} */ (1);
161+
var asConst2 = /** @type {const} */ ({
162+
x: 1
163+
});

tests/baselines/reference/jsdocTypeTagCast.symbols

+9
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,13 @@ if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
157157
}
158158

159159

160+
var asConst1 = /** @type {const} */(1);
161+
>asConst1 : Symbol(asConst1, Decl(b.js, 70, 3))
160162

163+
var asConst2 = /** @type {const} */({
164+
>asConst2 : Symbol(asConst2, Decl(b.js, 71, 3))
165+
166+
x: 1
167+
>x : Symbol(x, Decl(b.js, 71, 37))
168+
169+
});

tests/baselines/reference/jsdocTypeTagCast.types

+14
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,18 @@ if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
209209
}
210210

211211

212+
var asConst1 = /** @type {const} */(1);
213+
>asConst1 : 1
214+
>(1) : 1
215+
>1 : 1
212216

217+
var asConst2 = /** @type {const} */({
218+
>asConst2 : { x: number; }
219+
>({ x: 1}) : { x: number; }
220+
>{ x: 1} : { x: number; }
221+
222+
x: 1
223+
>x : number
224+
>1 : 1
225+
226+
});

tests/cases/conformance/jsdoc/jsdocTypeTagCast.ts

+4
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
7676
}
7777

7878

79+
var asConst1 = /** @type {const} */(1);
80+
var asConst2 = /** @type {const} */({
81+
x: 1
82+
});

0 commit comments

Comments
 (0)