JSDoc `@type` on a function: the type in a type predicate is never checked (unused `@import` reported, missing names not reported)
Evaluación
Este issue todavía no se ha evaluado.
Descripción
[!NOTE]
This issue was created by Claude (Anthropic's AI assistant), with direction from @ljharb. All compiler output below is from actualtscruns.
🔎 Search Terms
"declared but never used" jsdoc, TS6196, TS6133, TS2304, @import unused, jsdoc type predicate unused import, jsdoc type predicate "Cannot find name", @type function declaration type predicate, asserts jsdoc, noUnusedLocals checkJs, FullSignature
🕗 Version & Regression Information
- This changed between versions 6.0.3 and 7.0.2 (also reproduces on 7.1.0-dev.20260915.1)
⏯ Playground Link
No response (the repro needs a second file for the @import, plus a tsconfig)
💻 Code
// tsconfig.json
{
"compilerOptions": {
"module": "nodenext",
"allowJs": true,
"checkJs": true,
"noEmit": true,
"noUnusedLocals": true
}
}
// types.d.mts
export type Foo = Error & { code: 'X' };
// isFoo.mjs
/** @import { Foo } from './types.d.mts' */
/** @type {(e: unknown) => e is Foo} */
export function isFoo(e) {
return e instanceof Error && 'code' in e && e.code === 'X';
}
🙁 Actual behavior
isFoo.mjs(1,15): error TS6196: 'Foo' is declared but never used.
Foo is used, in the e is Foo type predicate of the @type tag.
🙂 Expected behavior
No error, as in 6.0.3.
Additional information about the issue
Each form below was tested in its own file with the same @import and tsconfig:
| Form | 7.1.0-dev.20260915.1 | 7.0.2 | 6.0.3 |
|---|---|---|---|
@type {(e: unknown) => e is Foo} on a function declaration (above) |
TS6196 | TS6196 | no error |
@type {(e: unknown) => asserts e is Foo} on a function declaration |
TS6196 | TS6196 | no error |
export default /** @type {(e: unknown) => e is Foo} */ (e) => … |
TS6196 | TS6196 | TS6133 |
@param {unknown} e + @returns {e is Foo} |
no error | no error | TS6133 |
JSDoc cast: /** @type {(e: unknown) => e is Foo} */ ((e) => …) |
no error | no error | no error |
@type {(e: Foo) => boolean} (Foo as a parameter type) |
no error | no error | no error |
| the first form, plus a call in the same file that narrows with it | no error | no error | no error |
Workaround: drop the @import and write e is import('./types.d.mts').Foo.
The predicate's type doesn't seem to be checked at all: names that don't exist aren't reported there either, while the same names in the parameter or return type are (same tsconfig, no imports):
// unchecked.mjs
/** @type {(e: unknown) => e is Missing1} */
export function a(e) {
return !!e;
}
/** @type {(e: unknown) => asserts e is Missing2} */
export function b(e) {
if (!e) {
throw new TypeError();
}
}
/** @type {(e: Missing3) => boolean} */
export function c(e) {
return !!e;
}
/** @type {(e: unknown) => Missing4} */
export function d(e) {
return /** @type {never} */ (e);
}
7.1.0-dev.20260915.1 and 7.0.2:
unchecked.mjs(13,16): error TS2304: Cannot find name 'Missing3'.
unchecked.mjs(18,28): error TS2304: Cannot find name 'Missing4'.
6.0.3:
unchecked.mjs(1,33): error TS2304: Cannot find name 'Missing1'.
unchecked.mjs(6,41): error TS2304: Cannot find name 'Missing2'.
unchecked.mjs(13,16): error TS2304: Cannot find name 'Missing3'.
unchecked.mjs(18,28): error TS2304: Cannot find name 'Missing4'.
Possibly relevant, but I haven't confirmed it: when a @type tag supplies a function's FullSignature, the checker only uses it for the argument-count check (checker.go#L3464-L3468, checker.go#L10320-L10324) and never runs checkSourceElement on it. If so, the predicate's type is never checked or marked as referenced unless something else resolves the predicate, like the same-file call in the last row of the table. #64052 (the open fix for #63754) edits these same lines, but only to strip undefined from the @type's type, so it wouldn't change this.
- Lenguaje dominante
- Go
- Estrellas
- 111k
- Forks
- 14.4k
- Merge medio
- 1 d 15 h
- PR fusionados (30 d)
- 106
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de microsoft/TypeScript
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
microsoft/TypeScript#64322 · 2 comentarios · 1 reacción · 2 asignados ·
-
Possible Improvement
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
microsoft/TypeScript#64278 · 1 comentario · 1 reacción ·
-
Docs
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
microsoft/TypeScript#64118 · 1 comentario ·
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
microsoft/TypeScript#64094 ·
-
Docs
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
microsoft/TypeScript#63959 · 5 comentarios ·
Todos los issues de microsoft/TypeScript
Issues similares
-
Type/Bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
OpenNSW/nsw-srilanka#497 ·
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
milvus-io/birdwatcher#545 ·
-
kind/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
kubernetes-sigs/prow#953 · 1 comentario ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
caddyserver/caddy#8046 ·