From 9906092db25aae8bd6f6b04aef5e8906251fcf13 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 3 Jun 2021 13:12:56 -0700 Subject: [PATCH] Add flag to change `catch` variables' default types to `unknown` (#41013) * Add test case for 'useUnknownInCatchVariables'. * Add new 'useUnknownInCatchVariables' flag. * Accepted baselines. * Add test for catch variable explicitly typed as 'any'. * Accepted baselines. * Move option under 'strict'. * Accepted baselines. * 'useUnknownInCatchVariables' is strict in command line help. --- src/compiler/checker.ts | 3 +- src/compiler/commandLineParser.ts | 9 ++ src/compiler/diagnosticMessages.json | 4 + src/compiler/types.ts | 1 + src/compiler/utilities.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + .../controlFlowForCatchAndFinally.types | 2 +- .../useUnknownInCatchVariables/tsconfig.json | 5 + .../tryCatchFinallyControlFlow.types | 30 +++--- .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + ...tatus.DiagnosticsPresent_OutputsSkipped.js | 1 + .../declarationDir-is-specified.js | 1 + ...-outDir-and-declarationDir-is-specified.js | 1 + .../when-outDir-is-specified.js | 1 + .../with-outFile.js | 1 + ...e-is-specified-with-declaration-enabled.js | 1 + .../without-outDir-or-outFile-is-specified.js | 1 + .../reference/typedefOnStatements.types | 2 +- .../useUnknownInCatchVariables01.errors.txt | 47 ++++++++ .../reference/useUnknownInCatchVariables01.js | 67 ++++++++++++ .../useUnknownInCatchVariables01.symbols | 71 ++++++++++++ .../useUnknownInCatchVariables01.types | 101 ++++++++++++++++++ .../compiler/useUnknownInCatchVariables01.ts | 35 ++++++ 32 files changed, 378 insertions(+), 18 deletions(-) create mode 100644 tests/baselines/reference/showConfig/Shows tsconfig for single option/useUnknownInCatchVariables/tsconfig.json create mode 100644 tests/baselines/reference/useUnknownInCatchVariables01.errors.txt create mode 100644 tests/baselines/reference/useUnknownInCatchVariables01.js create mode 100644 tests/baselines/reference/useUnknownInCatchVariables01.symbols create mode 100644 tests/baselines/reference/useUnknownInCatchVariables01.types create mode 100644 tests/cases/compiler/useUnknownInCatchVariables01.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2665d50aba1..38c193758be 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -346,6 +346,7 @@ namespace ts { const strictOptionalProperties = getStrictOptionValue(compilerOptions, "strictOptionalProperties"); const noImplicitAny = getStrictOptionValue(compilerOptions, "noImplicitAny"); const noImplicitThis = getStrictOptionValue(compilerOptions, "noImplicitThis"); + const useUnknownInCatchVariables = getStrictOptionValue(compilerOptions, "useUnknownInCatchVariables"); const keyofStringsOnly = !!compilerOptions.keyofStringsOnly; const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : ObjectFlags.FreshLiteral; @@ -9012,7 +9013,7 @@ namespace ts { if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) { const typeNode = getEffectiveTypeAnnotationNode(declaration); if (typeNode === undefined) { - return anyType; + return useUnknownInCatchVariables ? unknownType : anyType; } const type = getTypeOfNode(typeNode); // an errorType will make `checkTryStatement` issue an error diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 7ef4ec55924..ecd9e43c7f7 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -632,6 +632,15 @@ namespace ts { category: Diagnostics.Type_Checking, description: Diagnostics.Raise_error_on_this_expressions_with_an_implied_any_type, }, + { + name: "useUnknownInCatchVariables", + type: "boolean", + affectsSemanticDiagnostics: true, + strictFlag: true, + showInSimplifiedHelpView: true, + category: Diagnostics.Type_Checking, + description: Diagnostics.Type_catch_clause_variables_as_unknown_instead_of_any, + }, { name: "alwaysStrict", type: "boolean", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 3bbb2affe67..d2ddbc8b0a4 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -5198,6 +5198,10 @@ "category": "Message", "code": 6802 }, + "Type catch clause variables as 'unknown' instead of 'any'.": { + "category": "Message", + "code": 6803 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f2765d04ebc..e375b0a77ac 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6048,6 +6048,7 @@ namespace ts { /* @internal */ suppressOutputPathCheck?: boolean; target?: ScriptTarget; // TODO: GH#18217 frequently asserted as defined traceResolution?: boolean; + useUnknownInCatchVariables?: boolean; resolveJsonModule?: boolean; types?: string[]; /** Paths used to compute primary types search locations */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 1970b9db104..71689f76c70 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6088,6 +6088,7 @@ namespace ts { | "strictPropertyInitialization" | "strictOptionalProperties" | "alwaysStrict" + | "useUnknownInCatchVariables" ; export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d6ba9868cd4..376ebc37776 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2919,6 +2919,7 @@ declare namespace ts { suppressImplicitAnyIndexErrors?: boolean; target?: ScriptTarget; traceResolution?: boolean; + useUnknownInCatchVariables?: boolean; resolveJsonModule?: boolean; types?: string[]; /** Paths used to compute primary types search locations */ diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 9f58cc3bbab..ea5e5d3eeef 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2919,6 +2919,7 @@ declare namespace ts { suppressImplicitAnyIndexErrors?: boolean; target?: ScriptTarget; traceResolution?: boolean; + useUnknownInCatchVariables?: boolean; resolveJsonModule?: boolean; types?: string[]; /** Paths used to compute primary types search locations */ diff --git a/tests/baselines/reference/controlFlowForCatchAndFinally.types b/tests/baselines/reference/controlFlowForCatchAndFinally.types index a041cac8ce0..c159655a0a8 100644 --- a/tests/baselines/reference/controlFlowForCatchAndFinally.types +++ b/tests/baselines/reference/controlFlowForCatchAndFinally.types @@ -120,7 +120,7 @@ class Foo { >Aborter : typeof Aborter } catch (error) { ->error : any +>error : unknown if (this.abortController !== undefined) { >this.abortController !== undefined : boolean diff --git a/tests/baselines/reference/showConfig/Shows tsconfig for single option/useUnknownInCatchVariables/tsconfig.json b/tests/baselines/reference/showConfig/Shows tsconfig for single option/useUnknownInCatchVariables/tsconfig.json new file mode 100644 index 00000000000..19c7c22b692 --- /dev/null +++ b/tests/baselines/reference/showConfig/Shows tsconfig for single option/useUnknownInCatchVariables/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "useUnknownInCatchVariables": true + } +} diff --git a/tests/baselines/reference/tryCatchFinallyControlFlow.types b/tests/baselines/reference/tryCatchFinallyControlFlow.types index 1674907b3a2..b5fb0cf95cc 100644 --- a/tests/baselines/reference/tryCatchFinallyControlFlow.types +++ b/tests/baselines/reference/tryCatchFinallyControlFlow.types @@ -19,10 +19,10 @@ function f1() { >a : number } catch (e) { ->e : any +>e : unknown throw e; ->e : any +>e : unknown } finally { if (a != null && a.toFixed(0) == "123") { @@ -55,7 +55,7 @@ function f2() { >1 : 1 } catch (e) { ->e : any +>e : unknown x = 2; >x = 2 : 2 @@ -63,7 +63,7 @@ function f2() { >2 : 2 throw e; ->e : any +>e : unknown } finally { x; // 0 | 1 | 2 @@ -87,7 +87,7 @@ function f3() { >1 : 1 } catch (e) { ->e : any +>e : unknown x = 2; >x = 2 : 2 @@ -118,7 +118,7 @@ function f4() { >1 : 1 } catch (e) { ->e : any +>e : unknown x = 2; >x = 2 : 2 @@ -149,7 +149,7 @@ function f5() { return; } catch (e) { ->e : any +>e : unknown x = 2; >x = 2 : 2 @@ -178,7 +178,7 @@ function f6() { >1 : 1 } catch (e) { ->e : any +>e : unknown x = 2; >x = 2 : 2 @@ -211,7 +211,7 @@ function f7() { return; } catch (e) { ->e : any +>e : unknown x = 2; >x = 2 : 2 @@ -324,7 +324,7 @@ function f10() { return; } catch (e) { ->e : any +>e : unknown x = 2; >x = 2 : 2 @@ -388,7 +388,7 @@ function f11() { } } catch (e) { ->e : any +>e : unknown x; // 0 | 1 | 2 >x : 0 | 1 | 2 @@ -466,7 +466,7 @@ function f12() { } } catch (e) { ->e : any +>e : unknown x; // 0 | 1 | 2 >x : 0 | 1 | 2 @@ -576,7 +576,7 @@ function t1() { >'x' : "x" } catch (e) { ->e : any +>e : unknown return null; >null : null @@ -626,7 +626,7 @@ function notallowed(arg: number) { finally { } } catch (err) { ->err : any +>err : unknown state.tag; >state.tag : "one" | "two" | "three" @@ -770,7 +770,7 @@ function f21() { >x : 3 | 4 | 5 } catch (e) { ->e : any +>e : unknown x; // 0 | 1 | 2 | 3 | 4 | 5 >x : 0 | 1 | 2 | 3 | 4 | 5 diff --git a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json index f26c204d28d..6c8947c8c54 100644 --- a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json index 07a154df5b9..2a97b4825f7 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index 29328ff6625..78495516821 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index 9455ab8fead..2b4bc05d635 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json index 564f925485a..ead54b73278 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index 004a1d1bddc..8e8363326d7 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index f26c204d28d..6c8947c8c54 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index e1fea4afc37..c9f0dec383b 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json index 70c0c8e7491..112a8d7067a 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -81,6 +81,7 @@ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tsc/runWithoutArgs/initial-build/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js b/tests/baselines/reference/tsc/runWithoutArgs/initial-build/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js index db5d005ad3d..409bb21a72b 100644 --- a/tests/baselines/reference/tsc/runWithoutArgs/initial-build/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js +++ b/tests/baselines/reference/tsc/runWithoutArgs/initial-build/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js @@ -44,6 +44,7 @@ Options: --strictPropertyInitialization Enable strict checking of property initialization in classes. --strictOptionalProperties Enable strict checking of optional properties. --noImplicitThis Raise error on 'this' expressions with an implied 'any' type. + --useUnknownInCatchVariables Type catch clause variables as 'unknown' instead of 'any'. --alwaysStrict Parse in strict mode and emit "use strict" for each source file. --noUnusedLocals Report errors on unused locals. --noUnusedParameters Report errors on unused parameters. diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js index c0dbd442559..469659de728 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js @@ -102,6 +102,7 @@ interface Array { length: number; [n: number]: T; } // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js index e6854b8954b..bc09ff4894d 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js @@ -102,6 +102,7 @@ interface Array { length: number; [n: number]: T; } // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js index 2b51059cee8..7a5684c889a 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js @@ -102,6 +102,7 @@ interface Array { length: number; [n: number]: T; } // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js index 65430151ff6..e8a6ec3b509 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js @@ -102,6 +102,7 @@ interface Array { length: number; [n: number]: T; } // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js index 430697564a0..601d1b230ca 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js @@ -102,6 +102,7 @@ interface Array { length: number; [n: number]: T; } // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js index 375bc7f8a56..88362291291 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js @@ -102,6 +102,7 @@ interface Array { length: number; [n: number]: T; } // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictOptionalProperties": true, /* Enable strict checking of optional properties. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ diff --git a/tests/baselines/reference/typedefOnStatements.types b/tests/baselines/reference/typedefOnStatements.types index 007a6a41d76..c30a83a8afa 100644 --- a/tests/baselines/reference/typedefOnStatements.types +++ b/tests/baselines/reference/typedefOnStatements.types @@ -68,7 +68,7 @@ throw new Error('Unreachable') try { } catch (e) { ->e : any +>e : unknown } /** diff --git a/tests/baselines/reference/useUnknownInCatchVariables01.errors.txt b/tests/baselines/reference/useUnknownInCatchVariables01.errors.txt new file mode 100644 index 00000000000..017c3ada88c --- /dev/null +++ b/tests/baselines/reference/useUnknownInCatchVariables01.errors.txt @@ -0,0 +1,47 @@ +tests/cases/compiler/useUnknownInCatchVariables01.ts(6,12): error TS2339: Property 'toUpperCase' does not exist on type 'unknown'. +tests/cases/compiler/useUnknownInCatchVariables01.ts(7,10): error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type. +tests/cases/compiler/useUnknownInCatchVariables01.ts(8,10): error TS2349: This expression is not callable. + Type '{}' has no call signatures. + + +==== tests/cases/compiler/useUnknownInCatchVariables01.ts (3 errors) ==== + try { + // ... + } + catch (e) { + // error! + void e.toUpperCase(); + ~~~~~~~~~~~ +!!! error TS2339: Property 'toUpperCase' does not exist on type 'unknown'. + void e++; + ~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type. + void e(); + ~ +!!! error TS2349: This expression is not callable. +!!! error TS2349: Type '{}' has no call signatures. + + if (typeof e === "string") { + // works! + // We've narrowed 'e' down to the type 'string'. + console.log(e.toUpperCase()); + } + if (e instanceof Error) { + e.stack?.toUpperCase(); + } + if (typeof e === "number") { + e.toExponential(); + e++; + } + } + + + try { + // ... + } + catch (e: any) { + // All are allowed. + void e.toUpperCase(); + void e.toExponential(); + void e(); + } \ No newline at end of file diff --git a/tests/baselines/reference/useUnknownInCatchVariables01.js b/tests/baselines/reference/useUnknownInCatchVariables01.js new file mode 100644 index 00000000000..1e3a867d118 --- /dev/null +++ b/tests/baselines/reference/useUnknownInCatchVariables01.js @@ -0,0 +1,67 @@ +//// [useUnknownInCatchVariables01.ts] +try { + // ... +} +catch (e) { + // error! + void e.toUpperCase(); + void e++; + void e(); + + if (typeof e === "string") { + // works! + // We've narrowed 'e' down to the type 'string'. + console.log(e.toUpperCase()); + } + if (e instanceof Error) { + e.stack?.toUpperCase(); + } + if (typeof e === "number") { + e.toExponential(); + e++; + } +} + + +try { + // ... +} +catch (e: any) { + // All are allowed. + void e.toUpperCase(); + void e.toExponential(); + void e(); +} + +//// [useUnknownInCatchVariables01.js] +var _a; +try { + // ... +} +catch (e) { + // error! + void e.toUpperCase(); + void e++; + void e(); + if (typeof e === "string") { + // works! + // We've narrowed 'e' down to the type 'string'. + console.log(e.toUpperCase()); + } + if (e instanceof Error) { + (_a = e.stack) === null || _a === void 0 ? void 0 : _a.toUpperCase(); + } + if (typeof e === "number") { + e.toExponential(); + e++; + } +} +try { + // ... +} +catch (e) { + // All are allowed. + void e.toUpperCase(); + void e.toExponential(); + void e(); +} diff --git a/tests/baselines/reference/useUnknownInCatchVariables01.symbols b/tests/baselines/reference/useUnknownInCatchVariables01.symbols new file mode 100644 index 00000000000..f2261f8c36f --- /dev/null +++ b/tests/baselines/reference/useUnknownInCatchVariables01.symbols @@ -0,0 +1,71 @@ +=== tests/cases/compiler/useUnknownInCatchVariables01.ts === +try { + // ... +} +catch (e) { +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) + + // error! + void e.toUpperCase(); +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) + + void e++; +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) + + void e(); +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) + + if (typeof e === "string") { +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) + + // works! + // We've narrowed 'e' down to the type 'string'. + console.log(e.toUpperCase()); +>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, --, --)) +>e.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } + if (e instanceof Error) { +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + e.stack?.toUpperCase(); +>e.stack?.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>e.stack : Symbol(Error.stack, Decl(lib.es5.d.ts, --, --)) +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) +>stack : Symbol(Error.stack, Decl(lib.es5.d.ts, --, --)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } + if (typeof e === "number") { +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) + + e.toExponential(); +>e.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) +>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) + + e++; +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 3, 7)) + } +} + + +try { + // ... +} +catch (e: any) { +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 27, 7)) + + // All are allowed. + void e.toUpperCase(); +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 27, 7)) + + void e.toExponential(); +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 27, 7)) + + void e(); +>e : Symbol(e, Decl(useUnknownInCatchVariables01.ts, 27, 7)) +} diff --git a/tests/baselines/reference/useUnknownInCatchVariables01.types b/tests/baselines/reference/useUnknownInCatchVariables01.types new file mode 100644 index 00000000000..71a25687af0 --- /dev/null +++ b/tests/baselines/reference/useUnknownInCatchVariables01.types @@ -0,0 +1,101 @@ +=== tests/cases/compiler/useUnknownInCatchVariables01.ts === +try { + // ... +} +catch (e) { +>e : unknown + + // error! + void e.toUpperCase(); +>void e.toUpperCase() : undefined +>e.toUpperCase() : any +>e.toUpperCase : any +>e : unknown +>toUpperCase : any + + void e++; +>void e++ : undefined +>e++ : number +>e : unknown + + void e(); +>void e() : undefined +>e() : any +>e : unknown + + if (typeof e === "string") { +>typeof e === "string" : boolean +>typeof e : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>e : unknown +>"string" : "string" + + // works! + // We've narrowed 'e' down to the type 'string'. + console.log(e.toUpperCase()); +>console.log(e.toUpperCase()) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>e.toUpperCase() : string +>e.toUpperCase : () => string +>e : string +>toUpperCase : () => string + } + if (e instanceof Error) { +>e instanceof Error : boolean +>e : unknown +>Error : ErrorConstructor + + e.stack?.toUpperCase(); +>e.stack?.toUpperCase() : string +>e.stack?.toUpperCase : () => string +>e.stack : string +>e : Error +>stack : string +>toUpperCase : () => string + } + if (typeof e === "number") { +>typeof e === "number" : boolean +>typeof e : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>e : unknown +>"number" : "number" + + e.toExponential(); +>e.toExponential() : string +>e.toExponential : (fractionDigits?: number) => string +>e : number +>toExponential : (fractionDigits?: number) => string + + e++; +>e++ : number +>e : number + } +} + + +try { + // ... +} +catch (e: any) { +>e : any + + // All are allowed. + void e.toUpperCase(); +>void e.toUpperCase() : undefined +>e.toUpperCase() : any +>e.toUpperCase : any +>e : any +>toUpperCase : any + + void e.toExponential(); +>void e.toExponential() : undefined +>e.toExponential() : any +>e.toExponential : any +>e : any +>toExponential : any + + void e(); +>void e() : undefined +>e() : any +>e : any +} diff --git a/tests/cases/compiler/useUnknownInCatchVariables01.ts b/tests/cases/compiler/useUnknownInCatchVariables01.ts new file mode 100644 index 00000000000..ca9bdda4acb --- /dev/null +++ b/tests/cases/compiler/useUnknownInCatchVariables01.ts @@ -0,0 +1,35 @@ +// @useUnknownInCatchVariables: true + +try { + // ... +} +catch (e) { + // error! + void e.toUpperCase(); + void e++; + void e(); + + if (typeof e === "string") { + // works! + // We've narrowed 'e' down to the type 'string'. + console.log(e.toUpperCase()); + } + if (e instanceof Error) { + e.stack?.toUpperCase(); + } + if (typeof e === "number") { + e.toExponential(); + e++; + } +} + + +try { + // ... +} +catch (e: any) { + // All are allowed. + void e.toUpperCase(); + void e.toExponential(); + void e(); +} \ No newline at end of file