fix(39836): allow type declaration/unknown type in catch arguments in JavaScript files (#42392)

This commit is contained in:
Oleksandr T 2021-03-05 03:19:35 +02:00 committed by GitHub
parent 38fdce9440
commit ca8d9e4402
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 619 additions and 12 deletions

View File

@ -8847,9 +8847,11 @@ namespace ts {
Debug.assertIsDefined(symbol.valueDeclaration);
const declaration = symbol.valueDeclaration;
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
const decl = declaration as VariableDeclaration;
if (!decl.type) return anyType;
const type = getTypeOfNode(decl.type);
const typeNode = getEffectiveTypeAnnotationNode(declaration);
if (typeNode === undefined) {
return anyType;
}
const type = getTypeOfNode(typeNode);
// an errorType will make `checkTryStatement` issue an error
return isTypeAny(type) || type === unknownType ? type : errorType;
}
@ -36044,10 +36046,11 @@ namespace ts {
// Grammar checking
if (catchClause.variableDeclaration) {
const declaration = catchClause.variableDeclaration;
if (declaration.type) {
const typeNode = getEffectiveTypeAnnotationNode(getRootDeclaration(declaration));
if (typeNode) {
const type = getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ false);
if (type && !(type.flags & TypeFlags.AnyOrUnknown)) {
grammarErrorOnFirstToken(declaration.type, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified);
grammarErrorOnFirstToken(typeNode, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified);
}
}
else if (declaration.initializer) {

View File

@ -6279,6 +6279,7 @@ namespace ts {
function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration {
const pos = getNodePos();
const hasJSDoc = hasPrecedingJSDocComment();
const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations);
let exclamationToken: ExclamationToken | undefined;
if (allowExclamation && name.kind === SyntaxKind.Identifier &&
@ -6288,7 +6289,7 @@ namespace ts {
const type = parseTypeAnnotation();
const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer();
const node = factory.createVariableDeclaration(name, exclamationToken, type, initializer);
return finishNode(node, pos);
return withJSDoc(finishNode(node, pos), hasJSDoc);
}
function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList {

View File

@ -874,6 +874,7 @@ namespace ts {
| FunctionDeclaration
| ConstructorDeclaration
| MethodDeclaration
| VariableDeclaration
| PropertyDeclaration
| AccessorDeclaration
| ClassLikeDeclaration
@ -1237,7 +1238,7 @@ namespace ts {
export type BindingName = Identifier | BindingPattern;
export interface VariableDeclaration extends NamedDeclaration {
export interface VariableDeclaration extends NamedDeclaration, JSDocContainer {
readonly kind: SyntaxKind.VariableDeclaration;
readonly parent: VariableDeclarationList | CatchClause;
readonly name: BindingName; // Declared variable name

View File

@ -1204,7 +1204,8 @@ namespace ts {
node.kind === SyntaxKind.TypeParameter ||
node.kind === SyntaxKind.FunctionExpression ||
node.kind === SyntaxKind.ArrowFunction ||
node.kind === SyntaxKind.ParenthesizedExpression) ?
node.kind === SyntaxKind.ParenthesizedExpression ||
node.kind === SyntaxKind.VariableDeclaration) ?
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
getLeadingCommentRanges(text, node.pos);
// True if the comment starts with '/**' but not if it is '/**/'

View File

@ -558,7 +558,7 @@ declare namespace ts {
}
export interface JSDocContainer {
}
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | EndOfFileToken;
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | VariableDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | EndOfFileToken;
export type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
export type HasTypeArguments = CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement | JsxSelfClosingElement;
export type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
@ -687,7 +687,7 @@ declare namespace ts {
readonly kind: SyntaxKind.ConstructSignature;
}
export type BindingName = Identifier | BindingPattern;
export interface VariableDeclaration extends NamedDeclaration {
export interface VariableDeclaration extends NamedDeclaration, JSDocContainer {
readonly kind: SyntaxKind.VariableDeclaration;
readonly parent: VariableDeclarationList | CatchClause;
readonly name: BindingName;

View File

@ -558,7 +558,7 @@ declare namespace ts {
}
export interface JSDocContainer {
}
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | EndOfFileToken;
export type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | VariableDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | NamespaceExportDeclaration | ExportAssignment | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | NamedTupleMember | EndOfFileToken;
export type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
export type HasTypeArguments = CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement | JsxSelfClosingElement;
export type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
@ -687,7 +687,7 @@ declare namespace ts {
readonly kind: SyntaxKind.ConstructSignature;
}
export type BindingName = Identifier | BindingPattern;
export interface VariableDeclaration extends NamedDeclaration {
export interface VariableDeclaration extends NamedDeclaration, JSDocContainer {
readonly kind: SyntaxKind.VariableDeclaration;
readonly parent: VariableDeclarationList | CatchClause;
readonly name: BindingName;

View File

@ -0,0 +1,75 @@
tests/cases/conformance/jsdoc/foo.js(20,54): error TS2339: Property 'foo' does not exist on type 'unknown'.
tests/cases/conformance/jsdoc/foo.js(21,54): error TS2339: Property 'foo' does not exist on type 'unknown'.
tests/cases/conformance/jsdoc/foo.js(22,31): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
tests/cases/conformance/jsdoc/foo.js(23,31): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
tests/cases/conformance/jsdoc/foo.js(35,7): error TS2492: Cannot redeclare identifier 'err' in catch clause.
tests/cases/conformance/jsdoc/foo.js(48,31): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
tests/cases/conformance/jsdoc/foo.js(49,31): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
==== tests/cases/conformance/jsdoc/foo.js (7 errors) ====
/**
* @typedef {any} Any
*/
/**
* @typedef {unknown} Unknown
*/
function fn() {
try { } catch (x) { } // should be OK
try { } catch (/** @type {any} */ err) { } // should be OK
try { } catch (/** @type {Any} */ err) { } // should be OK
try { } catch (/** @type {unknown} */ err) { } // should be OK
try { } catch (/** @type {Unknown} */ err) { } // should be OK
try { } catch (err) { err.foo; } // should be OK
try { } catch (/** @type {any} */ err) { err.foo; } // should be OK
try { } catch (/** @type {Any} */ err) { err.foo; } // should be OK
try { } catch (/** @type {unknown} */ err) { console.log(err); } // should be OK
try { } catch (/** @type {Unknown} */ err) { console.log(err); } // should be OK
try { } catch (/** @type {unknown} */ err) { err.foo; } // error in the body
~~~
!!! error TS2339: Property 'foo' does not exist on type 'unknown'.
try { } catch (/** @type {Unknown} */ err) { err.foo; } // error in the body
~~~
!!! error TS2339: Property 'foo' does not exist on type 'unknown'.
try { } catch (/** @type {Error} */ err) { } // error in the type
~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
try { } catch (/** @type {object} */ err) { } // error in the type
~~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
try { console.log(); }
// @ts-ignore
catch (/** @type {number} */ err) { // e should not be a `number`
console.log(err.toLowerCase());
}
// minor bug: shows that the `catch` argument is skipped when checking scope
try { }
catch (err) {
/** @type {string} */
let err;
~~~
!!! error TS2492: Cannot redeclare identifier 'err' in catch clause.
}
try { }
catch (err) {
/** @type {boolean} */
var err;
}
try { } catch ({ x }) { } // should be OK
try { } catch (/** @type {any} */ { x }) { x.foo; } // should be OK
try { } catch (/** @type {Any} */ { x }) { x.foo;} // should be OK
try { } catch (/** @type {unknown} */ { x }) { console.log(x); } // should be OK
try { } catch (/** @type {Unknown} */ { x }) { console.log(x); } // should be OK
try { } catch (/** @type {Error} */ { x }) { } // error in the type
~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
try { } catch (/** @type {object} */ { x }) { } // error in the type
~~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
}

View File

@ -0,0 +1,144 @@
//// [foo.js]
/**
* @typedef {any} Any
*/
/**
* @typedef {unknown} Unknown
*/
function fn() {
try { } catch (x) { } // should be OK
try { } catch (/** @type {any} */ err) { } // should be OK
try { } catch (/** @type {Any} */ err) { } // should be OK
try { } catch (/** @type {unknown} */ err) { } // should be OK
try { } catch (/** @type {Unknown} */ err) { } // should be OK
try { } catch (err) { err.foo; } // should be OK
try { } catch (/** @type {any} */ err) { err.foo; } // should be OK
try { } catch (/** @type {Any} */ err) { err.foo; } // should be OK
try { } catch (/** @type {unknown} */ err) { console.log(err); } // should be OK
try { } catch (/** @type {Unknown} */ err) { console.log(err); } // should be OK
try { } catch (/** @type {unknown} */ err) { err.foo; } // error in the body
try { } catch (/** @type {Unknown} */ err) { err.foo; } // error in the body
try { } catch (/** @type {Error} */ err) { } // error in the type
try { } catch (/** @type {object} */ err) { } // error in the type
try { console.log(); }
// @ts-ignore
catch (/** @type {number} */ err) { // e should not be a `number`
console.log(err.toLowerCase());
}
// minor bug: shows that the `catch` argument is skipped when checking scope
try { }
catch (err) {
/** @type {string} */
let err;
}
try { }
catch (err) {
/** @type {boolean} */
var err;
}
try { } catch ({ x }) { } // should be OK
try { } catch (/** @type {any} */ { x }) { x.foo; } // should be OK
try { } catch (/** @type {Any} */ { x }) { x.foo;} // should be OK
try { } catch (/** @type {unknown} */ { x }) { console.log(x); } // should be OK
try { } catch (/** @type {Unknown} */ { x }) { console.log(x); } // should be OK
try { } catch (/** @type {Error} */ { x }) { } // error in the type
try { } catch (/** @type {object} */ { x }) { } // error in the type
}
//// [foo.js]
/**
* @typedef {any} Any
*/
/**
* @typedef {unknown} Unknown
*/
function fn() {
try { }
catch (x) { } // should be OK
try { }
catch ( /** @type {any} */err) { } // should be OK
try { }
catch ( /** @type {Any} */err) { } // should be OK
try { }
catch ( /** @type {unknown} */err) { } // should be OK
try { }
catch ( /** @type {Unknown} */err) { } // should be OK
try { }
catch (err) {
err.foo;
} // should be OK
try { }
catch ( /** @type {any} */err) {
err.foo;
} // should be OK
try { }
catch ( /** @type {Any} */err) {
err.foo;
} // should be OK
try { }
catch ( /** @type {unknown} */err) {
console.log(err);
} // should be OK
try { }
catch ( /** @type {Unknown} */err) {
console.log(err);
} // should be OK
try { }
catch ( /** @type {unknown} */err) {
err.foo;
} // error in the body
try { }
catch ( /** @type {Unknown} */err) {
err.foo;
} // error in the body
try { }
catch ( /** @type {Error} */err) { } // error in the type
try { }
catch ( /** @type {object} */err) { } // error in the type
try {
console.log();
}
// @ts-ignore
catch ( /** @type {number} */err) { // e should not be a `number`
console.log(err.toLowerCase());
}
// minor bug: shows that the `catch` argument is skipped when checking scope
try { }
catch (err) {
/** @type {string} */
let err;
}
try { }
catch (err) {
/** @type {boolean} */
var err;
}
try { }
catch ({ x }) { } // should be OK
try { }
catch ( /** @type {any} */{ x }) {
x.foo;
} // should be OK
try { }
catch ( /** @type {Any} */{ x }) {
x.foo;
} // should be OK
try { }
catch ( /** @type {unknown} */{ x }) {
console.log(x);
} // should be OK
try { }
catch ( /** @type {Unknown} */{ x }) {
console.log(x);
} // should be OK
try { }
catch ( /** @type {Error} */{ x }) { } // error in the type
try { }
catch ( /** @type {object} */{ x }) { } // error in the type
}

View File

@ -0,0 +1,133 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @typedef {any} Any
*/
/**
* @typedef {unknown} Unknown
*/
function fn() {
>fn : Symbol(fn, Decl(foo.js, 0, 0))
try { } catch (x) { } // should be OK
>x : Symbol(x, Decl(foo.js, 9, 19))
try { } catch (/** @type {any} */ err) { } // should be OK
>err : Symbol(err, Decl(foo.js, 10, 19))
try { } catch (/** @type {Any} */ err) { } // should be OK
>err : Symbol(err, Decl(foo.js, 11, 19))
try { } catch (/** @type {unknown} */ err) { } // should be OK
>err : Symbol(err, Decl(foo.js, 12, 19))
try { } catch (/** @type {Unknown} */ err) { } // should be OK
>err : Symbol(err, Decl(foo.js, 13, 19))
try { } catch (err) { err.foo; } // should be OK
>err : Symbol(err, Decl(foo.js, 14, 19))
>err : Symbol(err, Decl(foo.js, 14, 19))
try { } catch (/** @type {any} */ err) { err.foo; } // should be OK
>err : Symbol(err, Decl(foo.js, 15, 19))
>err : Symbol(err, Decl(foo.js, 15, 19))
try { } catch (/** @type {Any} */ err) { err.foo; } // should be OK
>err : Symbol(err, Decl(foo.js, 16, 19))
>err : Symbol(err, Decl(foo.js, 16, 19))
try { } catch (/** @type {unknown} */ err) { console.log(err); } // should be OK
>err : Symbol(err, Decl(foo.js, 17, 19))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>err : Symbol(err, Decl(foo.js, 17, 19))
try { } catch (/** @type {Unknown} */ err) { console.log(err); } // should be OK
>err : Symbol(err, Decl(foo.js, 18, 19))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>err : Symbol(err, Decl(foo.js, 18, 19))
try { } catch (/** @type {unknown} */ err) { err.foo; } // error in the body
>err : Symbol(err, Decl(foo.js, 19, 19))
>err : Symbol(err, Decl(foo.js, 19, 19))
try { } catch (/** @type {Unknown} */ err) { err.foo; } // error in the body
>err : Symbol(err, Decl(foo.js, 20, 19))
>err : Symbol(err, Decl(foo.js, 20, 19))
try { } catch (/** @type {Error} */ err) { } // error in the type
>err : Symbol(err, Decl(foo.js, 21, 19))
try { } catch (/** @type {object} */ err) { } // error in the type
>err : Symbol(err, Decl(foo.js, 22, 19))
try { console.log(); }
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
// @ts-ignore
catch (/** @type {number} */ err) { // e should not be a `number`
>err : Symbol(err, Decl(foo.js, 26, 11))
console.log(err.toLowerCase());
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>err : Symbol(err, Decl(foo.js, 26, 11))
}
// minor bug: shows that the `catch` argument is skipped when checking scope
try { }
catch (err) {
>err : Symbol(err, Decl(foo.js, 32, 8))
/** @type {string} */
let err;
>err : Symbol(err, Decl(foo.js, 34, 5))
}
try { }
catch (err) {
>err : Symbol(err, Decl(foo.js, 37, 8))
/** @type {boolean} */
var err;
>err : Symbol(err, Decl(foo.js, 39, 5))
}
try { } catch ({ x }) { } // should be OK
>x : Symbol(x, Decl(foo.js, 42, 20))
try { } catch (/** @type {any} */ { x }) { x.foo; } // should be OK
>x : Symbol(x, Decl(foo.js, 43, 39))
>x : Symbol(x, Decl(foo.js, 43, 39))
try { } catch (/** @type {Any} */ { x }) { x.foo;} // should be OK
>x : Symbol(x, Decl(foo.js, 44, 39))
>x : Symbol(x, Decl(foo.js, 44, 39))
try { } catch (/** @type {unknown} */ { x }) { console.log(x); } // should be OK
>x : Symbol(x, Decl(foo.js, 45, 43))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>x : Symbol(x, Decl(foo.js, 45, 43))
try { } catch (/** @type {Unknown} */ { x }) { console.log(x); } // should be OK
>x : Symbol(x, Decl(foo.js, 46, 43))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>x : Symbol(x, Decl(foo.js, 46, 43))
try { } catch (/** @type {Error} */ { x }) { } // error in the type
>x : Symbol(x, Decl(foo.js, 47, 41))
try { } catch (/** @type {object} */ { x }) { } // error in the type
>x : Symbol(x, Decl(foo.js, 48, 42))
}

View File

@ -0,0 +1,156 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @typedef {any} Any
*/
/**
* @typedef {unknown} Unknown
*/
function fn() {
>fn : () => void
try { } catch (x) { } // should be OK
>x : any
try { } catch (/** @type {any} */ err) { } // should be OK
>err : any
try { } catch (/** @type {Any} */ err) { } // should be OK
>err : any
try { } catch (/** @type {unknown} */ err) { } // should be OK
>err : unknown
try { } catch (/** @type {Unknown} */ err) { } // should be OK
>err : unknown
try { } catch (err) { err.foo; } // should be OK
>err : any
>err.foo : any
>err : any
>foo : any
try { } catch (/** @type {any} */ err) { err.foo; } // should be OK
>err : any
>err.foo : any
>err : any
>foo : any
try { } catch (/** @type {Any} */ err) { err.foo; } // should be OK
>err : any
>err.foo : any
>err : any
>foo : any
try { } catch (/** @type {unknown} */ err) { console.log(err); } // should be OK
>err : unknown
>console.log(err) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>err : unknown
try { } catch (/** @type {Unknown} */ err) { console.log(err); } // should be OK
>err : unknown
>console.log(err) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>err : unknown
try { } catch (/** @type {unknown} */ err) { err.foo; } // error in the body
>err : unknown
>err.foo : any
>err : unknown
>foo : any
try { } catch (/** @type {Unknown} */ err) { err.foo; } // error in the body
>err : unknown
>err.foo : any
>err : unknown
>foo : any
try { } catch (/** @type {Error} */ err) { } // error in the type
>err : any
try { } catch (/** @type {object} */ err) { } // error in the type
>err : any
try { console.log(); }
>console.log() : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
// @ts-ignore
catch (/** @type {number} */ err) { // e should not be a `number`
>err : any
console.log(err.toLowerCase());
>console.log(err.toLowerCase()) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>err.toLowerCase() : any
>err.toLowerCase : any
>err : any
>toLowerCase : any
}
// minor bug: shows that the `catch` argument is skipped when checking scope
try { }
catch (err) {
>err : any
/** @type {string} */
let err;
>err : string
}
try { }
catch (err) {
>err : any
/** @type {boolean} */
var err;
>err : boolean
}
try { } catch ({ x }) { } // should be OK
>x : any
try { } catch (/** @type {any} */ { x }) { x.foo; } // should be OK
>x : any
>x.foo : any
>x : any
>foo : any
try { } catch (/** @type {Any} */ { x }) { x.foo;} // should be OK
>x : any
>x.foo : any
>x : any
>foo : any
try { } catch (/** @type {unknown} */ { x }) { console.log(x); } // should be OK
>x : any
>console.log(x) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>x : any
try { } catch (/** @type {Unknown} */ { x }) { console.log(x); } // should be OK
>x : any
>console.log(x) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>x : any
try { } catch (/** @type {Error} */ { x }) { } // error in the type
>x : any
try { } catch (/** @type {object} */ { x }) { } // error in the type
>x : any
}

View File

@ -0,0 +1,10 @@
//// [foo.js]
/** @type {boolean} */
var /** @type {string} */ x,
/** @type {number} */ y;
//// [foo.js]
/** @type {boolean} */
var /** @type {string} */ x,
/** @type {number} */ y;

View File

@ -0,0 +1,8 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/** @type {boolean} */
var /** @type {string} */ x,
>x : Symbol(x, Decl(foo.js, 1, 3))
/** @type {number} */ y;
>y : Symbol(y, Decl(foo.js, 1, 28))

View File

@ -0,0 +1,8 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/** @type {boolean} */
var /** @type {string} */ x,
>x : string
/** @type {number} */ y;
>y : number

View File

@ -0,0 +1,57 @@
// @allowJs: true
// @checkJs: true
// @target: esnext
// @noImplicitAny: true
// @outDir: out
// @Filename: foo.js
/**
* @typedef {any} Any
*/
/**
* @typedef {unknown} Unknown
*/
function fn() {
try { } catch (x) { } // should be OK
try { } catch (/** @type {any} */ err) { } // should be OK
try { } catch (/** @type {Any} */ err) { } // should be OK
try { } catch (/** @type {unknown} */ err) { } // should be OK
try { } catch (/** @type {Unknown} */ err) { } // should be OK
try { } catch (err) { err.foo; } // should be OK
try { } catch (/** @type {any} */ err) { err.foo; } // should be OK
try { } catch (/** @type {Any} */ err) { err.foo; } // should be OK
try { } catch (/** @type {unknown} */ err) { console.log(err); } // should be OK
try { } catch (/** @type {Unknown} */ err) { console.log(err); } // should be OK
try { } catch (/** @type {unknown} */ err) { err.foo; } // error in the body
try { } catch (/** @type {Unknown} */ err) { err.foo; } // error in the body
try { } catch (/** @type {Error} */ err) { } // error in the type
try { } catch (/** @type {object} */ err) { } // error in the type
try { console.log(); }
// @ts-ignore
catch (/** @type {number} */ err) { // e should not be a `number`
console.log(err.toLowerCase());
}
// minor bug: shows that the `catch` argument is skipped when checking scope
try { }
catch (err) {
/** @type {string} */
let err;
}
try { }
catch (err) {
/** @type {boolean} */
var err;
}
try { } catch ({ x }) { } // should be OK
try { } catch (/** @type {any} */ { x }) { x.foo; } // should be OK
try { } catch (/** @type {Any} */ { x }) { x.foo;} // should be OK
try { } catch (/** @type {unknown} */ { x }) { console.log(x); } // should be OK
try { } catch (/** @type {Unknown} */ { x }) { console.log(x); } // should be OK
try { } catch (/** @type {Error} */ { x }) { } // error in the type
try { } catch (/** @type {object} */ { x }) { } // error in the type
}

View File

@ -0,0 +1,10 @@
// @allowJs: true
// @checkJs: true
// @target: esnext
// @noImplicitAny: true
// @outDir: out
// @Filename: foo.js
/** @type {boolean} */
var /** @type {string} */ x,
/** @type {number} */ y;