fix(60908): Unexpected "'Type' is declared but its value is never read." error with jsdoc @import syntax (#60921)

This commit is contained in:
Oleksandr T. 2025-03-17 22:29:48 +02:00 committed by GitHub
parent a00b324ab2
commit ee3dd7264b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 264 additions and 0 deletions

View File

@ -3951,6 +3951,10 @@ export function getContainerFlags(node: Node): ContainerFlags {
case SyntaxKind.ClassStaticBlockDeclaration:
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
case SyntaxKind.JSDocImportTag:
// treat as a container to prevent using an enclosing effective host, ensuring import bindings are scoped correctly
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals;
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression;

View File

@ -0,0 +1,38 @@
a.js(3,10): error TS6133: 'f1' is declared but its value is never read.
a.js(11,10): error TS6133: 'f3' is declared but its value is never read.
a.js(19,10): error TS6133: 'f4' is declared but its value is never read.
a.js(19,17): error TS2322: Type 'number' is not assignable to type 'string'.
==== types.d.ts (0 errors) ====
export type Foo = string;
==== a.js (4 errors) ====
/** @import { Foo } from './types.d.ts' */
function f1() { return undefined; }
~~
!!! error TS6133: 'f1' is declared but its value is never read.
export function f2() {
/** @type {Set<Foo>} */
const foo = new Set([ 'a', 'b' ]);
return foo;
}
function f3() { return undefined; }
~~
!!! error TS6133: 'f3' is declared but its value is never read.
/** @type {Set<Foo>} */
export const foo = new Set([ 'a', 'b' ]);
/**
* @returns {Foo}
*/
function f4() { return 1; }
~~
!!! error TS6133: 'f4' is declared but its value is never read.
~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.

View File

@ -0,0 +1,40 @@
//// [tests/cases/conformance/jsdoc/importTag24.ts] ////
=== types.d.ts ===
export type Foo = string;
>Foo : Symbol(Foo, Decl(types.d.ts, 0, 0))
=== a.js ===
/** @import { Foo } from './types.d.ts' */
function f1() { return undefined; }
>f1 : Symbol(f1, Decl(a.js, 0, 0))
>undefined : Symbol(undefined)
export function f2() {
>f2 : Symbol(f2, Decl(a.js, 2, 35))
/** @type {Set<Foo>} */
const foo = new Set([ 'a', 'b' ]);
>foo : Symbol(foo, Decl(a.js, 6, 9))
>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, --, --))
return foo;
>foo : Symbol(foo, Decl(a.js, 6, 9))
}
function f3() { return undefined; }
>f3 : Symbol(f3, Decl(a.js, 8, 1))
>undefined : Symbol(undefined)
/** @type {Set<Foo>} */
export const foo = new Set([ 'a', 'b' ]);
>foo : Symbol(foo, Decl(a.js, 13, 12))
>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, --, --))
/**
* @returns {Foo}
*/
function f4() { return 1; }
>f4 : Symbol(f4, Decl(a.js, 13, 41))

View File

@ -0,0 +1,74 @@
//// [tests/cases/conformance/jsdoc/importTag24.ts] ////
=== Performance Stats ===
Type Count: 1,000
Instantiation count: 2,500
=== types.d.ts ===
export type Foo = string;
>Foo : string
> : ^^^^^^
=== a.js ===
/** @import { Foo } from './types.d.ts' */
function f1() { return undefined; }
>f1 : () => any
> : ^^^^^^^^^
>undefined : undefined
> : ^^^^^^^^^
export function f2() {
>f2 : () => Set<string>
> : ^^^^^^^^^^^^^^^^^
/** @type {Set<Foo>} */
const foo = new Set([ 'a', 'b' ]);
>foo : Set<string>
> : ^^^^^^^^^^^
>new Set([ 'a', 'b' ]) : Set<string>
> : ^^^^^^^^^^^
>Set : SetConstructor
> : ^^^^^^^^^^^^^^
>[ 'a', 'b' ] : string[]
> : ^^^^^^^^
>'a' : "a"
> : ^^^
>'b' : "b"
> : ^^^
return foo;
>foo : Set<string>
> : ^^^^^^^^^^^
}
function f3() { return undefined; }
>f3 : () => any
> : ^^^^^^^^^
>undefined : undefined
> : ^^^^^^^^^
/** @type {Set<Foo>} */
export const foo = new Set([ 'a', 'b' ]);
>foo : Set<string>
> : ^^^^^^^^^^^
>new Set([ 'a', 'b' ]) : Set<string>
> : ^^^^^^^^^^^
>Set : SetConstructor
> : ^^^^^^^^^^^^^^
>[ 'a', 'b' ] : string[]
> : ^^^^^^^^
>'a' : "a"
> : ^^^
>'b' : "b"
> : ^^^
/**
* @returns {Foo}
*/
function f4() { return 1; }
>f4 : () => Foo
> : ^^^^^^^^^
>1 : 1
> : ^

View File

@ -0,0 +1,25 @@
//// [tests/cases/conformance/jsdoc/importTag25.ts] ////
=== types.d.ts ===
export type T = {
>T : Symbol(T, Decl(types.d.ts, 0, 0))
a: number;
>a : Symbol(a, Decl(types.d.ts, 0, 17))
};
=== foo.js ===
/** @import { T } from "./types.d.ts" */
export default async function f() {
>f : Symbol(f, Decl(foo.js, 0, 0))
/** @type {T[]} */
const types = [];
>types : Symbol(types, Decl(foo.js, 4, 6))
return types;
>types : Symbol(types, Decl(foo.js, 4, 6))
}

View File

@ -0,0 +1,32 @@
//// [tests/cases/conformance/jsdoc/importTag25.ts] ////
=== types.d.ts ===
export type T = {
>T : T
> : ^
a: number;
>a : number
> : ^^^^^^
};
=== foo.js ===
/** @import { T } from "./types.d.ts" */
export default async function f() {
>f : () => Promise<T[]>
> : ^^^^^^^^^^^^^^^^^^
/** @type {T[]} */
const types = [];
>types : T[]
> : ^^^
>[] : undefined[]
> : ^^^^^^^^^^^
return types;
>types : T[]
> : ^^^
}

View File

@ -0,0 +1,33 @@
// @checkJs: true
// @allowJs: true
// @noEmit: true
// @lib: esnext
// @moduleResolution: bundler
// @module: preserve
// @noUnusedLocals: true
// @noUnusedParameters: true
// @allowImportingTsExtensions: true
// @filename: types.d.ts
export type Foo = string;
// @filename: a.js
/** @import { Foo } from './types.d.ts' */
function f1() { return undefined; }
export function f2() {
/** @type {Set<Foo>} */
const foo = new Set([ 'a', 'b' ]);
return foo;
}
function f3() { return undefined; }
/** @type {Set<Foo>} */
export const foo = new Set([ 'a', 'b' ]);
/**
* @returns {Foo}
*/
function f4() { return 1; }

View File

@ -0,0 +1,18 @@
// @noUnusedLocals: true
// @allowJs: true
// @checkJs: true
// @noEmit: true
// @filename: types.d.ts
export type T = {
a: number;
};
// @filename: foo.js
/** @import { T } from "./types.d.ts" */
export default async function f() {
/** @type {T[]} */
const types = [];
return types;
}