diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 63d9ca101fcd7..e0e9382d378ed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7084,6 +7084,14 @@ namespace ts { return addOptionality(declaredType, isOptional); } + const jsDocTypeDefTag = getJSDocTypedefTag(declaration); + // The typedef is attached to a variable declaration, instead of specifying the name in the typedef itself + // This means that the variable declared references the typedef and should not be used in regular control + // flow of the program, only in jsdoc type references. + if (jsDocTypeDefTag && !jsDocTypeDefTag.name && isVariableDeclaration(declaration)) { + return neverType; + } + if ((noImplicitAny || isInJSFile(declaration)) && declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) && !(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !(declaration.flags & NodeFlags.Ambient)) { diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index cc36af32f2c77..d9fa516cebac8 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -716,6 +716,11 @@ namespace ts { return getFirstJSDocTag(node, isJSDocTemplateTag); } + /** Gets the JSDoc typedef tag for the node if present */ + export function getJSDocTypedefTag(node: Node): JSDocTypedefTag | undefined { + return getFirstJSDocTag(node, isJSDocTypedefTag); + } + /** Gets the JSDoc type tag for the node if present and valid */ export function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined { // We should have already issued an error if there were multiple type jsdocs, so just use the first one. diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 6d0038fe99fe4..36920f3b07c3b 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3524,6 +3524,8 @@ declare namespace ts { function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined; /** Gets the JSDoc template tag for the node if present */ function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined; + /** Gets the JSDoc typedef tag for the node if present */ + function getJSDocTypedefTag(node: Node): JSDocTypedefTag | undefined; /** Gets the JSDoc type tag for the node if present and valid */ function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined; /** diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 06556190efef4..c47c345a32e69 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3524,6 +3524,8 @@ declare namespace ts { function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined; /** Gets the JSDoc template tag for the node if present */ function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined; + /** Gets the JSDoc typedef tag for the node if present */ + function getJSDocTypedefTag(node: Node): JSDocTypedefTag | undefined; /** Gets the JSDoc type tag for the node if present and valid */ function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined; /** diff --git a/tests/baselines/reference/jsdocTypeDefNoImplicitAny.symbols b/tests/baselines/reference/jsdocTypeDefNoImplicitAny.symbols new file mode 100644 index 0000000000000..13caf4613e278 --- /dev/null +++ b/tests/baselines/reference/jsdocTypeDefNoImplicitAny.symbols @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/index.js === +/** @typedef {{foo: number}} */ +export let a; +>a : Symbol(a, Decl(index.js, 1, 10), Decl(index.js, 0, 4)) + +/** @typedef {number} */ +let b; +>b : Symbol(b, Decl(index.js, 3, 3), Decl(index.js, 2, 4)) + diff --git a/tests/baselines/reference/jsdocTypeDefNoImplicitAny.types b/tests/baselines/reference/jsdocTypeDefNoImplicitAny.types new file mode 100644 index 0000000000000..7e05294befd9b --- /dev/null +++ b/tests/baselines/reference/jsdocTypeDefNoImplicitAny.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/index.js === +/** @typedef {{foo: number}} */ +export let a; +>a : never + +/** @typedef {number} */ +let b; +>b : never + diff --git a/tests/baselines/reference/jsdocTypedefNoCrash.types b/tests/baselines/reference/jsdocTypedefNoCrash.types index e05c4421a794f..6fa716069c49f 100644 --- a/tests/baselines/reference/jsdocTypedefNoCrash.types +++ b/tests/baselines/reference/jsdocTypedefNoCrash.types @@ -4,6 +4,6 @@ * }} */ export const foo = 5; ->foo : 5 +>foo : never >5 : 5 diff --git a/tests/baselines/reference/jsdocTypedefNoCrash2.types b/tests/baselines/reference/jsdocTypedefNoCrash2.types index 374ff970aab56..699cc729cd6a4 100644 --- a/tests/baselines/reference/jsdocTypedefNoCrash2.types +++ b/tests/baselines/reference/jsdocTypedefNoCrash2.types @@ -7,6 +7,6 @@ export type foo = 5; * }} */ export const foo = 5; ->foo : 5 +>foo : never >5 : 5 diff --git a/tests/cases/conformance/jsdoc/jsdocTypeDefNoImplicitAny.ts b/tests/cases/conformance/jsdoc/jsdocTypeDefNoImplicitAny.ts new file mode 100644 index 0000000000000..df08c5cb9de52 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTypeDefNoImplicitAny.ts @@ -0,0 +1,9 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @noImplicitAny: true +// @Filename: index.js +/** @typedef {{foo: number}} */ +export let a; +/** @typedef {number} */ +let b; diff --git a/tests/cases/fourslash/jsdocTypedefTagSemanticMeaning1.ts b/tests/cases/fourslash/jsdocTypedefTagSemanticMeaning1.ts index 10b076c55f819..492bf6ca05f10 100644 --- a/tests/cases/fourslash/jsdocTypedefTagSemanticMeaning1.ts +++ b/tests/cases/fourslash/jsdocTypedefTagSemanticMeaning1.ts @@ -9,4 +9,4 @@ /////** @type {[|T|]} */ ////const n = [|T|]; -verify.singleReferenceGroup("type T = number\nconst T: 1", "T"); +verify.singleReferenceGroup("type T = number\nconst T: never", "T");