Skip to content

Commit ee3dd72

Browse files
authored
fix(60908): Unexpected "'Type' is declared but its value is never read." error with jsdoc @import syntax (#60921)
1 parent a00b324 commit ee3dd72

File tree

8 files changed

+264
-0
lines changed

8 files changed

+264
-0
lines changed

src/compiler/binder.ts

+4
Original file line numberDiff line numberDiff line change
@@ -3951,6 +3951,10 @@ export function getContainerFlags(node: Node): ContainerFlags {
39513951
case SyntaxKind.ClassStaticBlockDeclaration:
39523952
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
39533953

3954+
case SyntaxKind.JSDocImportTag:
3955+
// treat as a container to prevent using an enclosing effective host, ensuring import bindings are scoped correctly
3956+
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals;
3957+
39543958
case SyntaxKind.FunctionExpression:
39553959
case SyntaxKind.ArrowFunction:
39563960
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
a.js(3,10): error TS6133: 'f1' is declared but its value is never read.
2+
a.js(11,10): error TS6133: 'f3' is declared but its value is never read.
3+
a.js(19,10): error TS6133: 'f4' is declared but its value is never read.
4+
a.js(19,17): error TS2322: Type 'number' is not assignable to type 'string'.
5+
6+
7+
==== types.d.ts (0 errors) ====
8+
export type Foo = string;
9+
10+
==== a.js (4 errors) ====
11+
/** @import { Foo } from './types.d.ts' */
12+
13+
function f1() { return undefined; }
14+
~~
15+
!!! error TS6133: 'f1' is declared but its value is never read.
16+
17+
export function f2() {
18+
/** @type {Set<Foo>} */
19+
const foo = new Set([ 'a', 'b' ]);
20+
return foo;
21+
}
22+
23+
function f3() { return undefined; }
24+
~~
25+
!!! error TS6133: 'f3' is declared but its value is never read.
26+
27+
/** @type {Set<Foo>} */
28+
export const foo = new Set([ 'a', 'b' ]);
29+
30+
/**
31+
* @returns {Foo}
32+
*/
33+
function f4() { return 1; }
34+
~~
35+
!!! error TS6133: 'f4' is declared but its value is never read.
36+
~~~~~~
37+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
38+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/conformance/jsdoc/importTag24.ts] ////
2+
3+
=== types.d.ts ===
4+
export type Foo = string;
5+
>Foo : Symbol(Foo, Decl(types.d.ts, 0, 0))
6+
7+
=== a.js ===
8+
/** @import { Foo } from './types.d.ts' */
9+
10+
function f1() { return undefined; }
11+
>f1 : Symbol(f1, Decl(a.js, 0, 0))
12+
>undefined : Symbol(undefined)
13+
14+
export function f2() {
15+
>f2 : Symbol(f2, Decl(a.js, 2, 35))
16+
17+
/** @type {Set<Foo>} */
18+
const foo = new Set([ 'a', 'b' ]);
19+
>foo : Symbol(foo, Decl(a.js, 6, 9))
20+
>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --))
21+
22+
return foo;
23+
>foo : Symbol(foo, Decl(a.js, 6, 9))
24+
}
25+
26+
function f3() { return undefined; }
27+
>f3 : Symbol(f3, Decl(a.js, 8, 1))
28+
>undefined : Symbol(undefined)
29+
30+
/** @type {Set<Foo>} */
31+
export const foo = new Set([ 'a', 'b' ]);
32+
>foo : Symbol(foo, Decl(a.js, 13, 12))
33+
>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --))
34+
35+
/**
36+
* @returns {Foo}
37+
*/
38+
function f4() { return 1; }
39+
>f4 : Symbol(f4, Decl(a.js, 13, 41))
40+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//// [tests/cases/conformance/jsdoc/importTag24.ts] ////
2+
3+
=== Performance Stats ===
4+
Type Count: 1,000
5+
Instantiation count: 2,500
6+
7+
=== types.d.ts ===
8+
export type Foo = string;
9+
>Foo : string
10+
> : ^^^^^^
11+
12+
=== a.js ===
13+
/** @import { Foo } from './types.d.ts' */
14+
15+
function f1() { return undefined; }
16+
>f1 : () => any
17+
> : ^^^^^^^^^
18+
>undefined : undefined
19+
> : ^^^^^^^^^
20+
21+
export function f2() {
22+
>f2 : () => Set<string>
23+
> : ^^^^^^^^^^^^^^^^^
24+
25+
/** @type {Set<Foo>} */
26+
const foo = new Set([ 'a', 'b' ]);
27+
>foo : Set<string>
28+
> : ^^^^^^^^^^^
29+
>new Set([ 'a', 'b' ]) : Set<string>
30+
> : ^^^^^^^^^^^
31+
>Set : SetConstructor
32+
> : ^^^^^^^^^^^^^^
33+
>[ 'a', 'b' ] : string[]
34+
> : ^^^^^^^^
35+
>'a' : "a"
36+
> : ^^^
37+
>'b' : "b"
38+
> : ^^^
39+
40+
return foo;
41+
>foo : Set<string>
42+
> : ^^^^^^^^^^^
43+
}
44+
45+
function f3() { return undefined; }
46+
>f3 : () => any
47+
> : ^^^^^^^^^
48+
>undefined : undefined
49+
> : ^^^^^^^^^
50+
51+
/** @type {Set<Foo>} */
52+
export const foo = new Set([ 'a', 'b' ]);
53+
>foo : Set<string>
54+
> : ^^^^^^^^^^^
55+
>new Set([ 'a', 'b' ]) : Set<string>
56+
> : ^^^^^^^^^^^
57+
>Set : SetConstructor
58+
> : ^^^^^^^^^^^^^^
59+
>[ 'a', 'b' ] : string[]
60+
> : ^^^^^^^^
61+
>'a' : "a"
62+
> : ^^^
63+
>'b' : "b"
64+
> : ^^^
65+
66+
/**
67+
* @returns {Foo}
68+
*/
69+
function f4() { return 1; }
70+
>f4 : () => Foo
71+
> : ^^^^^^^^^
72+
>1 : 1
73+
> : ^
74+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [tests/cases/conformance/jsdoc/importTag25.ts] ////
2+
3+
=== types.d.ts ===
4+
export type T = {
5+
>T : Symbol(T, Decl(types.d.ts, 0, 0))
6+
7+
a: number;
8+
>a : Symbol(a, Decl(types.d.ts, 0, 17))
9+
10+
};
11+
12+
=== foo.js ===
13+
/** @import { T } from "./types.d.ts" */
14+
15+
export default async function f() {
16+
>f : Symbol(f, Decl(foo.js, 0, 0))
17+
18+
/** @type {T[]} */
19+
const types = [];
20+
>types : Symbol(types, Decl(foo.js, 4, 6))
21+
22+
return types;
23+
>types : Symbol(types, Decl(foo.js, 4, 6))
24+
}
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//// [tests/cases/conformance/jsdoc/importTag25.ts] ////
2+
3+
=== types.d.ts ===
4+
export type T = {
5+
>T : T
6+
> : ^
7+
8+
a: number;
9+
>a : number
10+
> : ^^^^^^
11+
12+
};
13+
14+
=== foo.js ===
15+
/** @import { T } from "./types.d.ts" */
16+
17+
export default async function f() {
18+
>f : () => Promise<T[]>
19+
> : ^^^^^^^^^^^^^^^^^^
20+
21+
/** @type {T[]} */
22+
const types = [];
23+
>types : T[]
24+
> : ^^^
25+
>[] : undefined[]
26+
> : ^^^^^^^^^^^
27+
28+
return types;
29+
>types : T[]
30+
> : ^^^
31+
}
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// @checkJs: true
2+
// @allowJs: true
3+
// @noEmit: true
4+
// @lib: esnext
5+
// @moduleResolution: bundler
6+
// @module: preserve
7+
// @noUnusedLocals: true
8+
// @noUnusedParameters: true
9+
// @allowImportingTsExtensions: true
10+
11+
// @filename: types.d.ts
12+
export type Foo = string;
13+
14+
// @filename: a.js
15+
/** @import { Foo } from './types.d.ts' */
16+
17+
function f1() { return undefined; }
18+
19+
export function f2() {
20+
/** @type {Set<Foo>} */
21+
const foo = new Set([ 'a', 'b' ]);
22+
return foo;
23+
}
24+
25+
function f3() { return undefined; }
26+
27+
/** @type {Set<Foo>} */
28+
export const foo = new Set([ 'a', 'b' ]);
29+
30+
/**
31+
* @returns {Foo}
32+
*/
33+
function f4() { return 1; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @noUnusedLocals: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @noEmit: true
5+
6+
// @filename: types.d.ts
7+
export type T = {
8+
a: number;
9+
};
10+
11+
// @filename: foo.js
12+
/** @import { T } from "./types.d.ts" */
13+
14+
export default async function f() {
15+
/** @type {T[]} */
16+
const types = [];
17+
return types;
18+
}

0 commit comments

Comments
 (0)