Skip to content

Commit

Permalink
Allow arbitrary catch clause type annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
jakebailey committed Jan 17, 2023
1 parent c7a4c13 commit db0c9b0
Show file tree
Hide file tree
Showing 9 changed files with 31 additions and 65 deletions.
15 changes: 2 additions & 13 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10206,11 +10206,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

// Use type from type annotation if one is present
const declaredType = tryGetTypeFromEffectiveTypeNode(declaration);
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
if (declaredType) {
// If the catch clause is explicitly annotated with any or unknown, accept it, otherwise error.
return isTypeAny(declaredType) || declaredType === unknownType ? declaredType : errorType;
}
if (!declaredType && isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
// If the catch clause is not explicitly annotated, treat it as though it were explicitly
// annotated with unknown or any, depending on useUnknownInCatchVariables.
return useUnknownInCatchVariables ? unknownType : anyType;
Expand Down Expand Up @@ -41179,14 +41175,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (catchClause.variableDeclaration) {
const declaration = catchClause.variableDeclaration;
checkVariableLikeDeclaration(declaration);
const typeNode = getEffectiveTypeAnnotationNode(declaration);
if (typeNode) {
const type = getTypeFromTypeNode(typeNode);
if (type && !(type.flags & TypeFlags.AnyOrUnknown)) {
grammarErrorOnFirstToken(typeNode, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified);
}
}
else if (declaration.initializer) {
if (declaration.initializer) {
grammarErrorOnFirstToken(declaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer);
}
else {
Expand Down
4 changes: 0 additions & 4 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -607,10 +607,6 @@
"category": "Error",
"code": 1195
},
"Catch clause variable type annotation must be 'any' or 'unknown' if specified.": {
"category": "Error",
"code": 1196
},
"Catch clause variable cannot have an initializer.": {
"category": "Error",
"code": 1197
Expand Down
23 changes: 10 additions & 13 deletions tests/baselines/reference/catchClauseWithTypeAnnotation.errors.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(17,36): error TS2339: Property 'foo' does not exist on type 'unknown'.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(18,37): error TS2339: Property 'foo' does not exist on type 'unknown'.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(19,23): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(20,23): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(25,23): error TS2339: Property 'toLowerCase' does not exist on type 'number'.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(29,29): error TS2492: Cannot redeclare identifier 'x' in catch clause.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(30,29): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type 'boolean', but here has type 'string'.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(36,22): error TS2339: Property 'x' does not exist on type '{}'.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(37,22): error TS2339: Property 'x' does not exist on type '{}'.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(38,27): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(39,27): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(38,22): error TS2339: Property 'x' does not exist on type '{}'.
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(39,22): error TS2339: Property 'x' does not exist on type 'Error'.


==== tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts (10 errors) ====
==== tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts (9 errors) ====
type any1 = any;
type unknown1 = unknown;

Expand All @@ -34,16 +33,14 @@ tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.t
~~~
!!! error TS2339: Property 'foo' does not exist on type 'unknown'.
try { } catch (x: Error) { } // error in the type
~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
try { } catch (x: object) { } // error in the type
~~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.

try { console.log(); }
// @ts-ignore
catch (e: number) { // e should not be a `number`
console.log(e.toLowerCase());
~~~~~~~~~~~
!!! error TS2339: Property 'toLowerCase' does not exist on type 'number'.
}

// minor bug: shows that the `catch` argument is skipped when checking scope
Expand All @@ -66,10 +63,10 @@ tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.t
~
!!! error TS2339: Property 'x' does not exist on type '{}'.
try { } catch ({ x }: object) { } // error in the type
~~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
~
!!! error TS2339: Property 'x' does not exist on type '{}'.
try { } catch ({ x }: Error) { } // error in the type
~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
~
!!! error TS2339: Property 'x' does not exist on type 'Error'.
}

8 changes: 4 additions & 4 deletions tests/baselines/reference/catchClauseWithTypeAnnotation.types
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ function fn(x: boolean) {
>foo : any

try { } catch (x: Error) { } // error in the type
>x : any
>x : Error

try { } catch (x: object) { } // error in the type
>x : any
>x : object

try { console.log(); }
>console.log() : void
Expand All @@ -85,7 +85,7 @@ function fn(x: boolean) {

// @ts-ignore
catch (e: number) { // e should not be a `number`
>e : any
>e : number

console.log(e.toLowerCase());
>console.log(e.toLowerCase()) : void
Expand All @@ -94,7 +94,7 @@ function fn(x: boolean) {
>log : (...data: any[]) => void
>e.toLowerCase() : any
>e.toLowerCase : any
>e : any
>e : number
>toLowerCase : any
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
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(28,25): error TS2339: Property 'toLowerCase' does not exist on type 'number'.
tests/cases/conformance/jsdoc/foo.js(35,7): error TS2492: Cannot redeclare identifier 'err' in catch clause.
tests/cases/conformance/jsdoc/foo.js(46,45): error TS2339: Property 'x' does not exist on type '{}'.
tests/cases/conformance/jsdoc/foo.js(47,45): error TS2339: Property 'x' does not exist on type '{}'.
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(48,43): error TS2339: Property 'x' does not exist on type 'Error'.
tests/cases/conformance/jsdoc/foo.js(49,44): error TS2339: Property 'x' does not exist on type '{}'.


==== tests/cases/conformance/jsdoc/foo.js (9 errors) ====
==== tests/cases/conformance/jsdoc/foo.js (8 errors) ====
/**
* @typedef {any} Any
*/
Expand All @@ -36,16 +35,14 @@ tests/cases/conformance/jsdoc/foo.js(49,31): error TS1196: Catch clause variable
~~~
!!! 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());
~~~~~~~~~~~
!!! error TS2339: Property 'toLowerCase' does not exist on type 'number'.
}

// minor bug: shows that the `catch` argument is skipped when checking scope
Expand All @@ -72,10 +69,10 @@ tests/cases/conformance/jsdoc/foo.js(49,31): error TS1196: Catch clause variable
~
!!! error TS2339: Property 'x' does not exist on type '{}'.
try { } catch (/** @type {Error} */ { x }) { } // error in the type
~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
~
!!! error TS2339: Property 'x' does not exist on type 'Error'.
try { } catch (/** @type {object} */ { x }) { } // error in the type
~~~~~~
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
~
!!! error TS2339: Property 'x' does not exist on type '{}'.
}

Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ function fn() {
>foo : any

try { } catch (/** @type {Error} */ err) { } // error in the type
>err : any
>err : Error

try { } catch (/** @type {object} */ err) { } // error in the type
>err : any
>err : object

try { console.log(); }
>console.log() : void
Expand All @@ -85,7 +85,7 @@ function fn() {

// @ts-ignore
catch (/** @type {number} */ err) { // e should not be a `number`
>err : any
>err : number

console.log(err.toLowerCase());
>console.log(err.toLowerCase()) : void
Expand All @@ -94,7 +94,7 @@ function fn() {
>log : (...data: any[]) => void
>err.toLowerCase() : any
>err.toLowerCase : any
>err : any
>err : number
>toLowerCase : any
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/parser/ecmascript5/CatchClauses/parserCatchClauseWithTypeAnnotation1.ts ===
try {
} catch (e: Error) {
>e : any
>e : Error
}

Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,6 @@ Info 32 [00:01:13.000] response:
"1193",
"1194",
"1195",
"1196",
"1197",
"1198",
"1199",
Expand Down Expand Up @@ -1887,7 +1886,6 @@ Info 38 [00:01:19.000] response:
"1193",
"1194",
"1195",
"1196",
"1197",
"1198",
"1199",
Expand Down Expand Up @@ -3133,7 +3131,6 @@ Info 40 [00:01:21.000] response:
"1193",
"1194",
"1195",
"1196",
"1197",
"1198",
"1199",
Expand Down

0 comments on commit db0c9b0

Please sign in to comment.