diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b7b659e1a6b3..85e33c5e4a1dd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8548,10 +8548,6 @@ namespace ts { } return type; } - // We never narrow type any in an instanceof guard - if (isTypeAny(type)) { - return type; - } // Check that right operand is a function type with a prototype property const rightType = checkExpression(expr.right); @@ -8569,6 +8565,11 @@ namespace ts { } } + // Don't narrow from 'any' if the target type is exactly 'Object' or 'Function' + if (isTypeAny(type) && (targetType === globalObjectType || targetType === globalFunctionType)) { + return type; + } + if (!targetType) { // Target type is type of construct signature let constructSignatures: Signature[]; @@ -8615,7 +8616,7 @@ namespace ts { } function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { - if (type.flags & TypeFlags.Any || !hasMatchingArgument(callExpression, reference)) { + if (!hasMatchingArgument(callExpression, reference)) { return type; } const signature = getResolvedSignature(callExpression); @@ -8623,6 +8624,12 @@ namespace ts { if (!predicate) { return type; } + + // Don't narrow from 'any' if the predicate type is exactly 'Object' or 'Function' + if (isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType)) { + return type; + } + if (isIdentifierTypePredicate(predicate)) { const predicateArgument = callExpression.arguments[predicate.parameterIndex]; if (predicateArgument) { diff --git a/tests/baselines/reference/narrowExceptionVariableInCatchClause.errors.txt b/tests/baselines/reference/narrowExceptionVariableInCatchClause.errors.txt new file mode 100644 index 0000000000000..e435b98050de6 --- /dev/null +++ b/tests/baselines/reference/narrowExceptionVariableInCatchClause.errors.txt @@ -0,0 +1,33 @@ +tests/cases/conformance/types/any/narrowExceptionVariableInCatchClause.ts(11,17): error TS2339: Property 'doPanic' does not exist on type '{ type: "foo"; dontPanic(): any; }'. +tests/cases/conformance/types/any/narrowExceptionVariableInCatchClause.ts(16,17): error TS2339: Property 'massage' does not exist on type 'Error'. + + +==== tests/cases/conformance/types/any/narrowExceptionVariableInCatchClause.ts (2 errors) ==== + declare function isFooError(x: any): x is { type: 'foo'; dontPanic(); }; + + function tryCatch() { + try { + // do stuff... + } + catch (err) { // err is implicitly 'any' and cannot be annotated + + if (isFooError(err)) { + err.dontPanic(); // OK + err.doPanic(); // ERROR: Property 'doPanic' does not exist on type '{...}' + ~~~~~~~ +!!! error TS2339: Property 'doPanic' does not exist on type '{ type: "foo"; dontPanic(): any; }'. + } + + else if (err instanceof Error) { + err.message; + err.massage; // ERROR: Property 'massage' does not exist on type 'Error' + ~~~~~~~ +!!! error TS2339: Property 'massage' does not exist on type 'Error'. + } + + else { + throw err; + } + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowExceptionVariableInCatchClause.js b/tests/baselines/reference/narrowExceptionVariableInCatchClause.js new file mode 100644 index 0000000000000..5808ed7682683 --- /dev/null +++ b/tests/baselines/reference/narrowExceptionVariableInCatchClause.js @@ -0,0 +1,44 @@ +//// [narrowExceptionVariableInCatchClause.ts] +declare function isFooError(x: any): x is { type: 'foo'; dontPanic(); }; + +function tryCatch() { + try { + // do stuff... + } + catch (err) { // err is implicitly 'any' and cannot be annotated + + if (isFooError(err)) { + err.dontPanic(); // OK + err.doPanic(); // ERROR: Property 'doPanic' does not exist on type '{...}' + } + + else if (err instanceof Error) { + err.message; + err.massage; // ERROR: Property 'massage' does not exist on type 'Error' + } + + else { + throw err; + } + } +} + + +//// [narrowExceptionVariableInCatchClause.js] +function tryCatch() { + try { + } + catch (err) { + if (isFooError(err)) { + err.dontPanic(); // OK + err.doPanic(); // ERROR: Property 'doPanic' does not exist on type '{...}' + } + else if (err instanceof Error) { + err.message; + err.massage; // ERROR: Property 'massage' does not exist on type 'Error' + } + else { + throw err; + } + } +} diff --git a/tests/baselines/reference/narrowFromAnyWithInstanceof.errors.txt b/tests/baselines/reference/narrowFromAnyWithInstanceof.errors.txt new file mode 100644 index 0000000000000..3e152b0faf456 --- /dev/null +++ b/tests/baselines/reference/narrowFromAnyWithInstanceof.errors.txt @@ -0,0 +1,33 @@ +tests/cases/conformance/types/any/narrowFromAnyWithInstanceof.ts(17,7): error TS2339: Property 'mesage' does not exist on type 'Error'. +tests/cases/conformance/types/any/narrowFromAnyWithInstanceof.ts(22,7): error TS2339: Property 'getHuors' does not exist on type 'Date'. + + +==== tests/cases/conformance/types/any/narrowFromAnyWithInstanceof.ts (2 errors) ==== + declare var x: any; + + if (x instanceof Function) { // 'any' is not narrowed when target type is 'Function' + x(); + x(1, 2, 3); + x("hello!"); + x.prop; + } + + if (x instanceof Object) { // 'any' is not narrowed when target type is 'Object' + x.method(); + x(); + } + + if (x instanceof Error) { // 'any' is narrowed to types other than 'Function'/'Object' + x.message; + x.mesage; + ~~~~~~ +!!! error TS2339: Property 'mesage' does not exist on type 'Error'. + } + + if (x instanceof Date) { + x.getDate(); + x.getHuors(); + ~~~~~~~~ +!!! error TS2339: Property 'getHuors' does not exist on type 'Date'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowFromAnyWithInstanceof.js b/tests/baselines/reference/narrowFromAnyWithInstanceof.js new file mode 100644 index 0000000000000..4cf1ca174aa02 --- /dev/null +++ b/tests/baselines/reference/narrowFromAnyWithInstanceof.js @@ -0,0 +1,45 @@ +//// [narrowFromAnyWithInstanceof.ts] +declare var x: any; + +if (x instanceof Function) { // 'any' is not narrowed when target type is 'Function' + x(); + x(1, 2, 3); + x("hello!"); + x.prop; +} + +if (x instanceof Object) { // 'any' is not narrowed when target type is 'Object' + x.method(); + x(); +} + +if (x instanceof Error) { // 'any' is narrowed to types other than 'Function'/'Object' + x.message; + x.mesage; +} + +if (x instanceof Date) { + x.getDate(); + x.getHuors(); +} + + +//// [narrowFromAnyWithInstanceof.js] +if (x instanceof Function) { + x(); + x(1, 2, 3); + x("hello!"); + x.prop; +} +if (x instanceof Object) { + x.method(); + x(); +} +if (x instanceof Error) { + x.message; + x.mesage; +} +if (x instanceof Date) { + x.getDate(); + x.getHuors(); +} diff --git a/tests/baselines/reference/narrowFromAnyWithTypePredicate.errors.txt b/tests/baselines/reference/narrowFromAnyWithTypePredicate.errors.txt new file mode 100644 index 0000000000000..94f41becdade8 --- /dev/null +++ b/tests/baselines/reference/narrowFromAnyWithTypePredicate.errors.txt @@ -0,0 +1,50 @@ +tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts(22,7): error TS2339: Property 'method' does not exist on type '{}'. +tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts(23,5): error TS2349: Cannot invoke an expression whose type lacks a call signature. +tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts(28,7): error TS2339: Property 'mesage' does not exist on type 'Error'. +tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts(33,7): error TS2339: Property 'getHuors' does not exist on type 'Date'. + + +==== tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts (4 errors) ==== + declare var x: any; + declare function isFunction(x): x is Function; + declare function isObject(x): x is Object; + declare function isAnything(x): x is {}; + declare function isError(x): x is Error; + declare function isDate(x): x is Date; + + + if (isFunction(x)) { // 'any' is not narrowed when target type is 'Function' + x(); + x(1, 2, 3); + x("hello!"); + x.prop; + } + + if (isObject(x)) { // 'any' is not narrowed when target type is 'Object' + x.method(); + x(); + } + + if (isAnything(x)) { // 'any' is narrowed to types other than 'Function'/'Object' (including {}) + x.method(); + ~~~~~~ +!!! error TS2339: Property 'method' does not exist on type '{}'. + x(); + ~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. + } + + if (isError(x)) { + x.message; + x.mesage; + ~~~~~~ +!!! error TS2339: Property 'mesage' does not exist on type 'Error'. + } + + if (isDate(x)) { + x.getDate(); + x.getHuors(); + ~~~~~~~~ +!!! error TS2339: Property 'getHuors' does not exist on type 'Date'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowFromAnyWithTypePredicate.js b/tests/baselines/reference/narrowFromAnyWithTypePredicate.js new file mode 100644 index 0000000000000..958a3cfd70daf --- /dev/null +++ b/tests/baselines/reference/narrowFromAnyWithTypePredicate.js @@ -0,0 +1,60 @@ +//// [narrowFromAnyWithTypePredicate.ts] +declare var x: any; +declare function isFunction(x): x is Function; +declare function isObject(x): x is Object; +declare function isAnything(x): x is {}; +declare function isError(x): x is Error; +declare function isDate(x): x is Date; + + +if (isFunction(x)) { // 'any' is not narrowed when target type is 'Function' + x(); + x(1, 2, 3); + x("hello!"); + x.prop; +} + +if (isObject(x)) { // 'any' is not narrowed when target type is 'Object' + x.method(); + x(); +} + +if (isAnything(x)) { // 'any' is narrowed to types other than 'Function'/'Object' (including {}) + x.method(); + x(); +} + +if (isError(x)) { + x.message; + x.mesage; +} + +if (isDate(x)) { + x.getDate(); + x.getHuors(); +} + + +//// [narrowFromAnyWithTypePredicate.js] +if (isFunction(x)) { + x(); + x(1, 2, 3); + x("hello!"); + x.prop; +} +if (isObject(x)) { + x.method(); + x(); +} +if (isAnything(x)) { + x.method(); + x(); +} +if (isError(x)) { + x.message; + x.mesage; +} +if (isDate(x)) { + x.getDate(); + x.getHuors(); +} diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt index c574118f91dc3..b67f73288560f 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt @@ -1,16 +1,26 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(12,10): error TS2339: Property 'bar' does not exist on type 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(18,10): error TS2339: Property 'bar' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(33,5): error TS2322: Type 'string' is not assignable to type 'number'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(34,10): error TS2339: Property 'bar' does not exist on type 'B'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(41,10): error TS2339: Property 'bar' does not exist on type 'B'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(66,10): error TS2339: Property 'bar2' does not exist on type 'C1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(72,10): error TS2339: Property 'bar1' does not exist on type 'C1 | C2'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(73,10): error TS2339: Property 'bar2' does not exist on type 'C1 | C2'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(85,10): error TS2339: Property 'bar' does not exist on type 'D'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(91,10): error TS2339: Property 'bar' does not exist on type 'D'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(112,10): error TS2339: Property 'bar2' does not exist on type 'E1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(118,11): error TS2339: Property 'bar1' does not exist on type 'E1 | E2'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(119,11): error TS2339: Property 'bar2' does not exist on type 'E1 | E2'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(134,11): error TS2339: Property 'foo' does not exist on type 'string | F'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(135,11): error TS2339: Property 'bar' does not exist on type 'string | F'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(160,11): error TS2339: Property 'foo2' does not exist on type 'G1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(166,11): error TS2339: Property 'foo2' does not exist on type 'G1'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(182,11): error TS2339: Property 'bar' does not exist on type 'H'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(187,11): error TS2339: Property 'foo1' does not exist on type 'H'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(188,11): error TS2339: Property 'foo2' does not exist on type 'H'. -==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (10 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (20 errors) ==== interface AConstructor { new (): A; } @@ -28,9 +38,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj2: any; - if (obj2 instanceof A) { // can't narrow type from 'any' + if (obj2 instanceof A) { obj2.foo; obj2.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'A'. } // a construct signature with generics @@ -54,10 +66,12 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj4: any; - if (obj4 instanceof B) { // can't narrow type from 'any' + if (obj4 instanceof B) { obj4.foo = "str"; obj4.foo = 1; obj4.bar = "str"; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'B'. } // has multiple construct signature @@ -88,10 +102,14 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj6: any; - if (obj6 instanceof C) { // can't narrow type from 'any' + if (obj6 instanceof C) { obj6.foo; obj6.bar1; + ~~~~ +!!! error TS2339: Property 'bar1' does not exist on type 'C1 | C2'. obj6.bar2; + ~~~~ +!!! error TS2339: Property 'bar2' does not exist on type 'C1 | C2'. } // with object type literal @@ -109,9 +127,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj8: any; - if (obj8 instanceof D) { // can't narrow type from 'any' + if (obj8 instanceof D) { obj8.foo; obj8.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'D'. } // a construct signature that returns a union type @@ -138,10 +158,14 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj10: any; - if (obj10 instanceof E) { // can't narrow type from 'any' + if (obj10 instanceof E) { obj10.foo; obj10.bar1; + ~~~~ +!!! error TS2339: Property 'bar1' does not exist on type 'E1 | E2'. obj10.bar2; + ~~~~ +!!! error TS2339: Property 'bar2' does not exist on type 'E1 | E2'. } // a construct signature that returns any @@ -165,7 +189,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj12: any; - if (obj12 instanceof F) { // can't narrow type from 'any' + if (obj12 instanceof F) { obj12.foo; obj12.bar; } @@ -192,9 +216,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj14: any; - if (obj14 instanceof G) { // can't narrow type from 'any' + if (obj14 instanceof G) { obj14.foo1; obj14.foo2; + ~~~~ +!!! error TS2339: Property 'foo2' does not exist on type 'G1'. } // a type with a prototype that has any type @@ -216,8 +242,24 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } var obj16: any; - if (obj16 instanceof H) { // can't narrow type from 'any' + if (obj16 instanceof H) { obj16.foo1; + ~~~~ +!!! error TS2339: Property 'foo1' does not exist on type 'H'. obj16.foo2; + ~~~~ +!!! error TS2339: Property 'foo2' does not exist on type 'H'. + } + + var obj17: any; + if (obj17 instanceof Object) { // can't narrow type from 'any' to 'Object' + obj17.foo1; + obj17.foo2; + } + + var obj18: any; + if (obj18 instanceof Function) { // can't narrow type from 'any' to 'Function' + obj18.foo1; + obj18.foo2; } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js index 7e6b332447062..40ef6587e75f7 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js @@ -14,7 +14,7 @@ if (obj1 instanceof A) { // narrowed to A. } var obj2: any; -if (obj2 instanceof A) { // can't narrow type from 'any' +if (obj2 instanceof A) { obj2.foo; obj2.bar; } @@ -36,7 +36,7 @@ if (obj3 instanceof B) { // narrowed to B. } var obj4: any; -if (obj4 instanceof B) { // can't narrow type from 'any' +if (obj4 instanceof B) { obj4.foo = "str"; obj4.foo = 1; obj4.bar = "str"; @@ -68,7 +68,7 @@ if (obj5 instanceof C) { // narrowed to C1|C2. } var obj6: any; -if (obj6 instanceof C) { // can't narrow type from 'any' +if (obj6 instanceof C) { obj6.foo; obj6.bar1; obj6.bar2; @@ -87,7 +87,7 @@ if (obj7 instanceof D) { // narrowed to D. } var obj8: any; -if (obj8 instanceof D) { // can't narrow type from 'any' +if (obj8 instanceof D) { obj8.foo; obj8.bar; } @@ -114,7 +114,7 @@ if (obj9 instanceof E) { // narrowed to E1 | E2 } var obj10: any; -if (obj10 instanceof E) { // can't narrow type from 'any' +if (obj10 instanceof E) { obj10.foo; obj10.bar1; obj10.bar2; @@ -137,7 +137,7 @@ if (obj11 instanceof F) { // can't type narrowing, construct signature returns a } var obj12: any; -if (obj12 instanceof F) { // can't narrow type from 'any' +if (obj12 instanceof F) { obj12.foo; obj12.bar; } @@ -162,7 +162,7 @@ if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype prop } var obj14: any; -if (obj14 instanceof G) { // can't narrow type from 'any' +if (obj14 instanceof G) { obj14.foo1; obj14.foo2; } @@ -184,10 +184,22 @@ if (obj15 instanceof H) { // narrowed to H. } var obj16: any; -if (obj16 instanceof H) { // can't narrow type from 'any' +if (obj16 instanceof H) { obj16.foo1; obj16.foo2; } + +var obj17: any; +if (obj17 instanceof Object) { // can't narrow type from 'any' to 'Object' + obj17.foo1; + obj17.foo2; +} + +var obj18: any; +if (obj18 instanceof Function) { // can't narrow type from 'any' to 'Function' + obj18.foo1; + obj18.foo2; +} //// [typeGuardsWithInstanceOfByConstructorSignature.js] @@ -278,3 +290,13 @@ if (obj16 instanceof H) { obj16.foo1; obj16.foo2; } +var obj17; +if (obj17 instanceof Object) { + obj17.foo1; + obj17.foo2; +} +var obj18; +if (obj18 instanceof Function) { + obj18.foo1; + obj18.foo2; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts index b81dd26652b0e..0817954c35c5c 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts @@ -13,7 +13,7 @@ if (obj1 instanceof A) { // narrowed to A. } var obj2: any; -if (obj2 instanceof A) { // can't narrow type from 'any' +if (obj2 instanceof A) { obj2.foo; obj2.bar; } @@ -35,7 +35,7 @@ if (obj3 instanceof B) { // narrowed to B. } var obj4: any; -if (obj4 instanceof B) { // can't narrow type from 'any' +if (obj4 instanceof B) { obj4.foo = "str"; obj4.foo = 1; obj4.bar = "str"; @@ -67,7 +67,7 @@ if (obj5 instanceof C) { // narrowed to C1|C2. } var obj6: any; -if (obj6 instanceof C) { // can't narrow type from 'any' +if (obj6 instanceof C) { obj6.foo; obj6.bar1; obj6.bar2; @@ -86,7 +86,7 @@ if (obj7 instanceof D) { // narrowed to D. } var obj8: any; -if (obj8 instanceof D) { // can't narrow type from 'any' +if (obj8 instanceof D) { obj8.foo; obj8.bar; } @@ -113,7 +113,7 @@ if (obj9 instanceof E) { // narrowed to E1 | E2 } var obj10: any; -if (obj10 instanceof E) { // can't narrow type from 'any' +if (obj10 instanceof E) { obj10.foo; obj10.bar1; obj10.bar2; @@ -136,7 +136,7 @@ if (obj11 instanceof F) { // can't type narrowing, construct signature returns a } var obj12: any; -if (obj12 instanceof F) { // can't narrow type from 'any' +if (obj12 instanceof F) { obj12.foo; obj12.bar; } @@ -161,7 +161,7 @@ if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype prop } var obj14: any; -if (obj14 instanceof G) { // can't narrow type from 'any' +if (obj14 instanceof G) { obj14.foo1; obj14.foo2; } @@ -183,7 +183,19 @@ if (obj15 instanceof H) { // narrowed to H. } var obj16: any; -if (obj16 instanceof H) { // can't narrow type from 'any' +if (obj16 instanceof H) { obj16.foo1; obj16.foo2; } + +var obj17: any; +if (obj17 instanceof Object) { // can't narrow type from 'any' to 'Object' + obj17.foo1; + obj17.foo2; +} + +var obj18: any; +if (obj18 instanceof Function) { // can't narrow type from 'any' to 'Function' + obj18.foo1; + obj18.foo2; +} diff --git a/tests/cases/conformance/types/any/narrowExceptionVariableInCatchClause.ts b/tests/cases/conformance/types/any/narrowExceptionVariableInCatchClause.ts new file mode 100644 index 0000000000000..dfa60a415f91a --- /dev/null +++ b/tests/cases/conformance/types/any/narrowExceptionVariableInCatchClause.ts @@ -0,0 +1,23 @@ +declare function isFooError(x: any): x is { type: 'foo'; dontPanic(); }; + +function tryCatch() { + try { + // do stuff... + } + catch (err) { // err is implicitly 'any' and cannot be annotated + + if (isFooError(err)) { + err.dontPanic(); // OK + err.doPanic(); // ERROR: Property 'doPanic' does not exist on type '{...}' + } + + else if (err instanceof Error) { + err.message; + err.massage; // ERROR: Property 'massage' does not exist on type 'Error' + } + + else { + throw err; + } + } +} diff --git a/tests/cases/conformance/types/any/narrowFromAnyWithInstanceof.ts b/tests/cases/conformance/types/any/narrowFromAnyWithInstanceof.ts new file mode 100644 index 0000000000000..4fbfc46060a80 --- /dev/null +++ b/tests/cases/conformance/types/any/narrowFromAnyWithInstanceof.ts @@ -0,0 +1,23 @@ +declare var x: any; + +if (x instanceof Function) { // 'any' is not narrowed when target type is 'Function' + x(); + x(1, 2, 3); + x("hello!"); + x.prop; +} + +if (x instanceof Object) { // 'any' is not narrowed when target type is 'Object' + x.method(); + x(); +} + +if (x instanceof Error) { // 'any' is narrowed to types other than 'Function'/'Object' + x.message; + x.mesage; +} + +if (x instanceof Date) { + x.getDate(); + x.getHuors(); +} diff --git a/tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts b/tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts new file mode 100644 index 0000000000000..473bd349b5f91 --- /dev/null +++ b/tests/cases/conformance/types/any/narrowFromAnyWithTypePredicate.ts @@ -0,0 +1,34 @@ +declare var x: any; +declare function isFunction(x): x is Function; +declare function isObject(x): x is Object; +declare function isAnything(x): x is {}; +declare function isError(x): x is Error; +declare function isDate(x): x is Date; + + +if (isFunction(x)) { // 'any' is not narrowed when target type is 'Function' + x(); + x(1, 2, 3); + x("hello!"); + x.prop; +} + +if (isObject(x)) { // 'any' is not narrowed when target type is 'Object' + x.method(); + x(); +} + +if (isAnything(x)) { // 'any' is narrowed to types other than 'Function'/'Object' (including {}) + x.method(); + x(); +} + +if (isError(x)) { + x.message; + x.mesage; +} + +if (isDate(x)) { + x.getDate(); + x.getHuors(); +}