From 35d6e98e98f49de24ff7e443f589fc19fd9cfd2b Mon Sep 17 00:00:00 2001 From: vvakame Date: Thu, 30 Apr 2015 13:27:07 +0900 Subject: [PATCH 1/5] type narrowing by constructor signiture of interface --- src/compiler/checker.ts | 40 +++-- ...nstanceOfByConstructorSignature.errors.txt | 111 ++++++++++++++ ...rdsWithInstanceOfByConstructorSignature.js | 137 ++++++++++++++++++ ...rdsWithInstanceOfByConstructorSignature.ts | 89 ++++++++++++ 4 files changed, 368 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt create mode 100644 tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 469ecf80c84..36f9bbb654b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5351,17 +5351,39 @@ module ts { } // Target type is type of prototype property let prototypeProperty = getPropertyOfType(rightType, "prototype"); - if (!prototypeProperty) { - return type; + if (prototypeProperty) { + let targetType = getTypeOfSymbol(prototypeProperty); + if (targetType !== anyType) { + // Narrow to target type if it is a subtype of current type + if (isTypeSubtypeOf(targetType, type)) { + return targetType; + } + // If current type is a union type, remove all constituents that aren't subtypes of target type + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, targetType))); + } + } } - let targetType = getTypeOfSymbol(prototypeProperty); - // Narrow to target type if it is a subtype of current type - if (isTypeSubtypeOf(targetType, type)) { - return targetType; + // Target type is type of constructor signiture + let constructorSignitures: Signature[]; + if (rightType.flags & TypeFlags.Interface) { + constructorSignitures = (rightType).declaredConstructSignatures; } - // If current type is a union type, remove all constituents that aren't subtypes of target type - if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, targetType))); + if (rightType.flags & TypeFlags.Anonymous) { + constructorSignitures = (rightType).constructSignatures; + } + if (constructorSignitures) { + let constructorType = getUnionType(map(constructorSignitures, constructorSignature => { + if (constructorSignature.typeParameters && constructorSignature.typeParameters.length !== 0) { + // TODO convert type parameters to any or empty object types. e.g. Sample -> Sample or Sample<{}>. + } + return constructorSignature.resolvedReturnType; + })); + // Pickup type from union types + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, constructorType))); + } + return constructorType; } return type; } diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt new file mode 100644 index 00000000000..c7146541705 --- /dev/null +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt @@ -0,0 +1,111 @@ +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(32,10): error TS2339: Property 'foo' does not exist on type '{}'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(33,10): error TS2339: Property 'foo' does not exist on type '{}'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(34,10): error TS2339: Property 'bar' does not exist on type '{}'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(63,10): error TS2339: Property 'bar2' does not exist on type 'C1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(82,10): error TS2339: Property 'bar' does not exist on type 'D'. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (6 errors) ==== + interface AConstructor { + new (): A; + } + interface A { + foo: string; + } + declare var A: AConstructor; + + var obj1: A | string; + if (obj1 instanceof A) { // narrowed to A. + obj1.foo; + obj1.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'A'. + } + + var obj2: any; + if (obj2 instanceof A) { // can't type narrowing from any. + obj2.foo; + obj2.bar; + } + + // with generics + interface BConstructor { + new (): B; + } + interface B { + foo: T; + } + declare var B: BConstructor; + + var obj3: B | A; + if (obj3 instanceof B) { // narrowed to B. + obj3.foo = "str"; + ~~~ +!!! error TS2339: Property 'foo' does not exist on type '{}'. + obj3.foo = 1; + ~~~ +!!! error TS2339: Property 'foo' does not exist on type '{}'. + obj3.bar = "str"; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type '{}'. + } + + var obj4: any; + if (obj4 instanceof B) { // can't type narrowing from any. + obj4.foo = "str"; + obj4.foo = 1; + obj4.bar = "str"; + } + + // has multiple constructor signature + interface CConstructor { + new (value: string): C1; + new (value: number): C2; + } + interface C1 { + foo: string; + bar1: number; + } + interface C2 { + foo: string; + bar2: number; + } + declare var C: CConstructor; + + var obj5: C1 | A; + if (obj5 instanceof C) { // narrowed to C1. + obj5.foo; + obj5.bar1; + obj5.bar2; + ~~~~ +!!! error TS2339: Property 'bar2' does not exist on type 'C1'. + } + + var obj6: any; + if (obj6 instanceof C) { // can't type narrowing from any. + obj6.foo; + obj6.bar1; + obj6.bar2; + } + + // with object type literal + interface D { + foo: string; + } + declare var D: { new (): D; }; + + var obj7: D | string; + if (obj7 instanceof D) { // narrowed to D. + obj7.foo; + obj7.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'D'. + } + + var obj8: any; + if (obj8 instanceof D) { // can't type narrowing from any. + obj8.foo; + obj8.bar; + } + \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js new file mode 100644 index 00000000000..c795126b0ff --- /dev/null +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js @@ -0,0 +1,137 @@ +//// [typeGuardsWithInstanceOfByConstructorSignature.ts] +interface AConstructor { + new (): A; +} +interface A { + foo: string; +} +declare var A: AConstructor; + +var obj1: A | string; +if (obj1 instanceof A) { // narrowed to A. + obj1.foo; + obj1.bar; +} + +var obj2: any; +if (obj2 instanceof A) { // can't type narrowing from any. + obj2.foo; + obj2.bar; +} + +// with generics +interface BConstructor { + new (): B; +} +interface B { + foo: T; +} +declare var B: BConstructor; + +var obj3: B | A; +if (obj3 instanceof B) { // narrowed to B. + obj3.foo = "str"; + obj3.foo = 1; + obj3.bar = "str"; +} + +var obj4: any; +if (obj4 instanceof B) { // can't type narrowing from any. + obj4.foo = "str"; + obj4.foo = 1; + obj4.bar = "str"; +} + +// has multiple constructor signature +interface CConstructor { + new (value: string): C1; + new (value: number): C2; +} +interface C1 { + foo: string; + bar1: number; +} +interface C2 { + foo: string; + bar2: number; +} +declare var C: CConstructor; + +var obj5: C1 | A; +if (obj5 instanceof C) { // narrowed to C1. + obj5.foo; + obj5.bar1; + obj5.bar2; +} + +var obj6: any; +if (obj6 instanceof C) { // can't type narrowing from any. + obj6.foo; + obj6.bar1; + obj6.bar2; +} + +// with object type literal +interface D { + foo: string; +} +declare var D: { new (): D; }; + +var obj7: D | string; +if (obj7 instanceof D) { // narrowed to D. + obj7.foo; + obj7.bar; +} + +var obj8: any; +if (obj8 instanceof D) { // can't type narrowing from any. + obj8.foo; + obj8.bar; +} + + +//// [typeGuardsWithInstanceOfByConstructorSignature.js] +var obj1; +if (obj1 instanceof A) { + obj1.foo; + obj1.bar; +} +var obj2; +if (obj2 instanceof A) { + obj2.foo; + obj2.bar; +} +var obj3; +if (obj3 instanceof B) { + obj3.foo = "str"; + obj3.foo = 1; + obj3.bar = "str"; +} +var obj4; +if (obj4 instanceof B) { + obj4.foo = "str"; + obj4.foo = 1; + obj4.bar = "str"; +} +var obj5; +if (obj5 instanceof C) { + obj5.foo; + obj5.bar1; + obj5.bar2; +} +var obj6; +if (obj6 instanceof C) { + obj6.foo; + obj6.bar1; + obj6.bar2; +} +var obj7; +if (obj7 instanceof D) { + obj7.foo; + obj7.bar; +} +var obj8; +if (obj8 instanceof D) { + obj8.foo; + obj8.bar; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts new file mode 100644 index 00000000000..b28d92e2c8e --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts @@ -0,0 +1,89 @@ +interface AConstructor { + new (): A; +} +interface A { + foo: string; +} +declare var A: AConstructor; + +var obj1: A | string; +if (obj1 instanceof A) { // narrowed to A. + obj1.foo; + obj1.bar; +} + +var obj2: any; +if (obj2 instanceof A) { // can't type narrowing from any. + obj2.foo; + obj2.bar; +} + +// with generics +interface BConstructor { + new (): B; +} +interface B { + foo: T; +} +declare var B: BConstructor; + +var obj3: B | A; +if (obj3 instanceof B) { // narrowed to B. + obj3.foo = "str"; + obj3.foo = 1; + obj3.bar = "str"; +} + +var obj4: any; +if (obj4 instanceof B) { // can't type narrowing from any. + obj4.foo = "str"; + obj4.foo = 1; + obj4.bar = "str"; +} + +// has multiple constructor signature +interface CConstructor { + new (value: string): C1; + new (value: number): C2; +} +interface C1 { + foo: string; + bar1: number; +} +interface C2 { + foo: string; + bar2: number; +} +declare var C: CConstructor; + +var obj5: C1 | A; +if (obj5 instanceof C) { // narrowed to C1. + obj5.foo; + obj5.bar1; + obj5.bar2; +} + +var obj6: any; +if (obj6 instanceof C) { // can't type narrowing from any. + obj6.foo; + obj6.bar1; + obj6.bar2; +} + +// with object type literal +interface D { + foo: string; +} +declare var D: { new (): D; }; + +var obj7: D | string; +if (obj7 instanceof D) { // narrowed to D. + obj7.foo; + obj7.bar; +} + +var obj8: any; +if (obj8 instanceof D) { // can't type narrowing from any. + obj8.foo; + obj8.bar; +} From ab10d509f5368137af5c50e532616e1d0fb9e45a Mon Sep 17 00:00:00 2001 From: vvakame Date: Sat, 2 May 2015 15:27:06 +0900 Subject: [PATCH 2/5] support instantiate signature, it has type parameters. --- src/compiler/checker.ts | 20 +-- ...nstanceOfByConstructorSignature.errors.txt | 137 ++++++++++++++-- ...rdsWithInstanceOfByConstructorSignature.js | 151 +++++++++++++++++- ...rdsWithInstanceOfByConstructorSignature.ts | 107 ++++++++++++- 4 files changed, 380 insertions(+), 35 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 36f9bbb654b..c864a8aa76a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5365,25 +5365,25 @@ module ts { } } // Target type is type of constructor signiture - let constructorSignitures: Signature[]; + let constructSignitures: Signature[]; if (rightType.flags & TypeFlags.Interface) { - constructorSignitures = (rightType).declaredConstructSignatures; + constructSignitures = (rightType).declaredConstructSignatures; } if (rightType.flags & TypeFlags.Anonymous) { - constructorSignitures = (rightType).constructSignatures; + constructSignitures = (rightType).constructSignatures; } - if (constructorSignitures) { - let constructorType = getUnionType(map(constructorSignitures, constructorSignature => { - if (constructorSignature.typeParameters && constructorSignature.typeParameters.length !== 0) { - // TODO convert type parameters to any or empty object types. e.g. Sample -> Sample or Sample<{}>. + if (constructSignitures) { + let instanceType = getUnionType(map(constructSignitures, constructSignature => { + if (constructSignature.typeParameters && constructSignature.typeParameters.length !== 0) { + constructSignature = instantiateSignature(constructSignature, createTypeMapper(constructSignature.typeParameters, map(constructSignature.typeParameters, _ => anyType)), true) } - return constructorSignature.resolvedReturnType; + return constructSignature.resolvedReturnType; })); // Pickup type from union types if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, constructorType))); + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, instanceType))); } - return constructorType; + return instanceType; } return type; } diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt index c7146541705..1816ef77fc2 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt @@ -1,12 +1,16 @@ 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(32,10): error TS2339: Property 'foo' does not exist on type '{}'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(33,10): error TS2339: Property 'foo' does not exist on type '{}'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(34,10): error TS2339: Property 'bar' does not exist on type '{}'. +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(63,10): error TS2339: Property 'bar2' does not exist on type 'C1'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(82,10): error TS2339: Property 'bar' does not exist on type 'D'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(109,10): error TS2339: Property 'bar2' does not exist on type 'E1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(131,11): error TS2339: Property 'foo' does not exist on type 'string | F'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(132,11): error TS2339: Property 'bar' does not exist on type 'string | F'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(157,11): error TS2339: Property 'foo2' does not exist on type 'G1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(179,11): error TS2339: Property 'bar' does not exist on type 'H'. -==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (6 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (10 errors) ==== interface AConstructor { new (): A; } @@ -29,7 +33,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru obj2.bar; } - // with generics + // a construct signature with generics interface BConstructor { new (): B; } @@ -38,17 +42,15 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru } declare var B: BConstructor; - var obj3: B | A; - if (obj3 instanceof B) { // narrowed to B. - obj3.foo = "str"; - ~~~ -!!! error TS2339: Property 'foo' does not exist on type '{}'. + var obj3: B | string; + if (obj3 instanceof B) { // narrowed to B. obj3.foo = 1; - ~~~ -!!! error TS2339: Property 'foo' does not exist on type '{}'. + obj3.foo = "str"; + ~~~~~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'number'. obj3.bar = "str"; ~~~ -!!! error TS2339: Property 'bar' does not exist on type '{}'. +!!! error TS2339: Property 'bar' does not exist on type 'B'. } var obj4: any; @@ -58,7 +60,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru obj4.bar = "str"; } - // has multiple constructor signature + // has multiple construct signature interface CConstructor { new (value: string): C1; new (value: number): C2; @@ -108,4 +110,111 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru obj8.foo; obj8.bar; } + + // a construct signature that returns a union type + interface EConstructor { + new (): E1 | E2; + } + interface E1 { + foo: string; + bar1: number; + } + interface E2 { + foo: string; + bar2: number; + } + declare var E: EConstructor; + + var obj9: E1 | A; + if (obj9 instanceof E) { // narrowed to E1. + obj9.foo; + obj9.bar1; + obj9.bar2; + ~~~~ +!!! error TS2339: Property 'bar2' does not exist on type 'E1'. + } + + var obj10: any; + if (obj10 instanceof E) { // can't type narrowing from any. + obj10.foo; + obj10.bar1; + obj10.bar2; + } + + // a construct signature that returns any + interface FConstructor { + new (): any; + } + interface F { + foo: string; + bar: number; + } + declare var F: FConstructor; + + var obj11: F | string; + if (obj11 instanceof F) { // can't type narrowing, construct signiture returns any. + obj11.foo; + ~~~ +!!! error TS2339: Property 'foo' does not exist on type 'string | F'. + obj11.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'string | F'. + } + + var obj12: any; + if (obj12 instanceof F) { // can't type narrowing from any. + obj12.foo; + obj12.bar; + } + + // a type with a prototype, it overrides the construct signiture + interface GConstructor { + prototype: G1; // high priority + new (): G2; // low priority + } + interface G1 { + foo1: number; + } + interface G2 { + foo2: boolean; + } + declare var G: GConstructor; + + var obj13: G1 | G2; + if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype property. + obj13.foo1; + obj13.foo2; + ~~~~ +!!! error TS2339: Property 'foo2' does not exist on type 'G1'. + } + + var obj14: any; + if (obj14 instanceof G) { // can't type narrowing from any. + obj14.foo1; + obj14.foo2; + } + + // a type with a prototype that has any type + interface HConstructor { + prototype: any; // high priority, but any type is ignored. interface has implicit `prototype: any`. + new (): H; // low priority + } + interface H { + foo: number; + } + declare var H: HConstructor; + + var obj15: H | string; + if (obj15 instanceof H) { // narrowed to H. + obj15.foo; + obj15.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'H'. + } + + var obj16: any; + if (obj16 instanceof H) { // can't type narrowing from any. + obj16.foo1; + obj16.foo2; + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js index c795126b0ff..395a5e96e05 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js @@ -19,7 +19,7 @@ if (obj2 instanceof A) { // can't type narrowing from any. obj2.bar; } -// with generics +// a construct signature with generics interface BConstructor { new (): B; } @@ -28,10 +28,10 @@ interface B { } declare var B: BConstructor; -var obj3: B | A; -if (obj3 instanceof B) { // narrowed to B. - obj3.foo = "str"; +var obj3: B | string; +if (obj3 instanceof B) { // narrowed to B. obj3.foo = 1; + obj3.foo = "str"; obj3.bar = "str"; } @@ -42,7 +42,7 @@ if (obj4 instanceof B) { // can't type narrowing from any. obj4.bar = "str"; } -// has multiple constructor signature +// has multiple construct signature interface CConstructor { new (value: string): C1; new (value: number): C2; @@ -89,6 +89,103 @@ if (obj8 instanceof D) { // can't type narrowing from any. obj8.bar; } +// a construct signature that returns a union type +interface EConstructor { + new (): E1 | E2; +} +interface E1 { + foo: string; + bar1: number; +} +interface E2 { + foo: string; + bar2: number; +} +declare var E: EConstructor; + +var obj9: E1 | A; +if (obj9 instanceof E) { // narrowed to E1. + obj9.foo; + obj9.bar1; + obj9.bar2; +} + +var obj10: any; +if (obj10 instanceof E) { // can't type narrowing from any. + obj10.foo; + obj10.bar1; + obj10.bar2; +} + +// a construct signature that returns any +interface FConstructor { + new (): any; +} +interface F { + foo: string; + bar: number; +} +declare var F: FConstructor; + +var obj11: F | string; +if (obj11 instanceof F) { // can't type narrowing, construct signiture returns any. + obj11.foo; + obj11.bar; +} + +var obj12: any; +if (obj12 instanceof F) { // can't type narrowing from any. + obj12.foo; + obj12.bar; +} + +// a type with a prototype, it overrides the construct signiture +interface GConstructor { + prototype: G1; // high priority + new (): G2; // low priority +} +interface G1 { + foo1: number; +} +interface G2 { + foo2: boolean; +} +declare var G: GConstructor; + +var obj13: G1 | G2; +if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype property. + obj13.foo1; + obj13.foo2; +} + +var obj14: any; +if (obj14 instanceof G) { // can't type narrowing from any. + obj14.foo1; + obj14.foo2; +} + +// a type with a prototype that has any type +interface HConstructor { + prototype: any; // high priority, but any type is ignored. interface has implicit `prototype: any`. + new (): H; // low priority +} +interface H { + foo: number; +} +declare var H: HConstructor; + +var obj15: H | string; +if (obj15 instanceof H) { // narrowed to H. + obj15.foo; + obj15.bar; +} + +var obj16: any; +if (obj16 instanceof H) { // can't type narrowing from any. + obj16.foo1; + obj16.foo2; +} + //// [typeGuardsWithInstanceOfByConstructorSignature.js] var obj1; @@ -103,8 +200,8 @@ if (obj2 instanceof A) { } var obj3; if (obj3 instanceof B) { - obj3.foo = "str"; obj3.foo = 1; + obj3.foo = "str"; obj3.bar = "str"; } var obj4; @@ -135,3 +232,45 @@ if (obj8 instanceof D) { obj8.foo; obj8.bar; } +var obj9; +if (obj9 instanceof E) { + obj9.foo; + obj9.bar1; + obj9.bar2; +} +var obj10; +if (obj10 instanceof E) { + obj10.foo; + obj10.bar1; + obj10.bar2; +} +var obj11; +if (obj11 instanceof F) { + obj11.foo; + obj11.bar; +} +var obj12; +if (obj12 instanceof F) { + obj12.foo; + obj12.bar; +} +var obj13; +if (obj13 instanceof G) { + obj13.foo1; + obj13.foo2; +} +var obj14; +if (obj14 instanceof G) { + obj14.foo1; + obj14.foo2; +} +var obj15; +if (obj15 instanceof H) { + obj15.foo; + obj15.bar; +} +var obj16; +if (obj16 instanceof H) { + obj16.foo1; + obj16.foo2; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts index b28d92e2c8e..c432ceb2bda 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts @@ -18,7 +18,7 @@ if (obj2 instanceof A) { // can't type narrowing from any. obj2.bar; } -// with generics +// a construct signature with generics interface BConstructor { new (): B; } @@ -27,10 +27,10 @@ interface B { } declare var B: BConstructor; -var obj3: B | A; -if (obj3 instanceof B) { // narrowed to B. - obj3.foo = "str"; +var obj3: B | string; +if (obj3 instanceof B) { // narrowed to B. obj3.foo = 1; + obj3.foo = "str"; obj3.bar = "str"; } @@ -41,7 +41,7 @@ if (obj4 instanceof B) { // can't type narrowing from any. obj4.bar = "str"; } -// has multiple constructor signature +// has multiple construct signature interface CConstructor { new (value: string): C1; new (value: number): C2; @@ -87,3 +87,100 @@ if (obj8 instanceof D) { // can't type narrowing from any. obj8.foo; obj8.bar; } + +// a construct signature that returns a union type +interface EConstructor { + new (): E1 | E2; +} +interface E1 { + foo: string; + bar1: number; +} +interface E2 { + foo: string; + bar2: number; +} +declare var E: EConstructor; + +var obj9: E1 | A; +if (obj9 instanceof E) { // narrowed to E1. + obj9.foo; + obj9.bar1; + obj9.bar2; +} + +var obj10: any; +if (obj10 instanceof E) { // can't type narrowing from any. + obj10.foo; + obj10.bar1; + obj10.bar2; +} + +// a construct signature that returns any +interface FConstructor { + new (): any; +} +interface F { + foo: string; + bar: number; +} +declare var F: FConstructor; + +var obj11: F | string; +if (obj11 instanceof F) { // can't type narrowing, construct signiture returns any. + obj11.foo; + obj11.bar; +} + +var obj12: any; +if (obj12 instanceof F) { // can't type narrowing from any. + obj12.foo; + obj12.bar; +} + +// a type with a prototype, it overrides the construct signiture +interface GConstructor { + prototype: G1; // high priority + new (): G2; // low priority +} +interface G1 { + foo1: number; +} +interface G2 { + foo2: boolean; +} +declare var G: GConstructor; + +var obj13: G1 | G2; +if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype property. + obj13.foo1; + obj13.foo2; +} + +var obj14: any; +if (obj14 instanceof G) { // can't type narrowing from any. + obj14.foo1; + obj14.foo2; +} + +// a type with a prototype that has any type +interface HConstructor { + prototype: any; // high priority, but any type is ignored. interface has implicit `prototype: any`. + new (): H; // low priority +} +interface H { + foo: number; +} +declare var H: HConstructor; + +var obj15: H | string; +if (obj15 instanceof H) { // narrowed to H. + obj15.foo; + obj15.bar; +} + +var obj16: any; +if (obj16 instanceof H) { // can't type narrowing from any. + obj16.foo1; + obj16.foo2; +} From 880ccf0221f482322d97da238abc26f64b731381 Mon Sep 17 00:00:00 2001 From: vvakame Date: Tue, 5 May 2015 20:29:43 +0900 Subject: [PATCH 3/5] PR feedback --- src/compiler/checker.ts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c864a8aa76a..eac5d563357 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3599,6 +3599,10 @@ module ts { return type; } + function getUnionTypeOfSubtypeConstituents(source: UnionType, target: Type): Type { + return getUnionType(filter(source.types, t => isTypeSubtypeOf(t, target))); + } + function getReducedTypeOfUnionType(type: UnionType): Type { // If union type was created without subtype reduction, perform the deferred reduction now if (!type.reducedType) { @@ -5354,26 +5358,26 @@ module ts { if (prototypeProperty) { let targetType = getTypeOfSymbol(prototypeProperty); if (targetType !== anyType) { - // Narrow to target type if it is a subtype of current type + // Narrow to the target type if it's a subtype of the current type if (isTypeSubtypeOf(targetType, type)) { return targetType; } - // If current type is a union type, remove all constituents that aren't subtypes of target type + // If the current type is a union type, remove all constituents that aren't subtypes of the target. if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, targetType))); + return getUnionTypeOfSubtypeConstituents(type, targetType); } } } // Target type is type of constructor signiture - let constructSignitures: Signature[]; + let constructSignatures: Signature[]; if (rightType.flags & TypeFlags.Interface) { - constructSignitures = (rightType).declaredConstructSignatures; + constructSignatures = (rightType).declaredConstructSignatures; + } else if (rightType.flags & TypeFlags.Anonymous) { + constructSignatures = (rightType).constructSignatures; } - if (rightType.flags & TypeFlags.Anonymous) { - constructSignitures = (rightType).constructSignatures; - } - if (constructSignitures) { - let instanceType = getUnionType(map(constructSignitures, constructSignature => { + + if (constructSignatures) { + let instanceType = getUnionType(map(constructSignatures, constructSignature => { if (constructSignature.typeParameters && constructSignature.typeParameters.length !== 0) { constructSignature = instantiateSignature(constructSignature, createTypeMapper(constructSignature.typeParameters, map(constructSignature.typeParameters, _ => anyType)), true) } @@ -5381,7 +5385,7 @@ module ts { })); // Pickup type from union types if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, instanceType))); + return getUnionTypeOfSubtypeConstituents(type, instanceType); } return instanceType; } From e342c955625b10523cf753fa63982c1092502bee Mon Sep 17 00:00:00 2001 From: vvakame Date: Wed, 6 May 2015 01:00:17 +0900 Subject: [PATCH 4/5] fix code styling --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eac5d563357..c279786c686 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5372,7 +5372,8 @@ module ts { let constructSignatures: Signature[]; if (rightType.flags & TypeFlags.Interface) { constructSignatures = (rightType).declaredConstructSignatures; - } else if (rightType.flags & TypeFlags.Anonymous) { + } + else if (rightType.flags & TypeFlags.Anonymous) { constructSignatures = (rightType).constructSignatures; } From 776f390786f1dc71236b4c124084a20da225d0ae Mon Sep 17 00:00:00 2001 From: vvakame Date: Wed, 6 May 2015 20:28:03 +0900 Subject: [PATCH 5/5] PR feedback --- src/compiler/checker.ts | 15 +- ...nstanceOfByConstructorSignature.errors.txt | 438 +++++++++--------- ...rdsWithInstanceOfByConstructorSignature.js | 200 ++++---- ...rdsWithInstanceOfByConstructorSignature.ts | 20 +- 4 files changed, 334 insertions(+), 339 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c279786c686..eba6c954671 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5368,22 +5368,17 @@ module ts { } } } - // Target type is type of constructor signiture + // Target type is type of construct signature let constructSignatures: Signature[]; if (rightType.flags & TypeFlags.Interface) { - constructSignatures = (rightType).declaredConstructSignatures; + constructSignatures = resolveDeclaredMembers(rightType).declaredConstructSignatures; } else if (rightType.flags & TypeFlags.Anonymous) { - constructSignatures = (rightType).constructSignatures; + constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct); } - if (constructSignatures) { - let instanceType = getUnionType(map(constructSignatures, constructSignature => { - if (constructSignature.typeParameters && constructSignature.typeParameters.length !== 0) { - constructSignature = instantiateSignature(constructSignature, createTypeMapper(constructSignature.typeParameters, map(constructSignature.typeParameters, _ => anyType)), true) - } - return constructSignature.resolvedReturnType; - })); + if (constructSignatures && constructSignatures.length !== 0) { + let instanceType = getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))); // Pickup type from union types if (type.flags & TypeFlags.Union) { return getUnionTypeOfSubtypeConstituents(type, instanceType); diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt index 1816ef77fc2..b963b2c33ae 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt @@ -1,220 +1,220 @@ -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(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(63,10): error TS2339: Property 'bar2' does not exist on type 'C1'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(82,10): error TS2339: Property 'bar' does not exist on type 'D'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(109,10): error TS2339: Property 'bar2' does not exist on type 'E1'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(131,11): error TS2339: Property 'foo' does not exist on type 'string | F'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(132,11): error TS2339: Property 'bar' does not exist on type 'string | F'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(157,11): error TS2339: Property 'foo2' does not exist on type 'G1'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(179,11): error TS2339: Property 'bar' does not exist on type 'H'. - - -==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (10 errors) ==== - interface AConstructor { - new (): A; - } - interface A { - foo: string; - } - declare var A: AConstructor; - - var obj1: A | string; - if (obj1 instanceof A) { // narrowed to A. - obj1.foo; - obj1.bar; - ~~~ -!!! error TS2339: Property 'bar' does not exist on type 'A'. - } - - var obj2: any; - if (obj2 instanceof A) { // can't type narrowing from any. - obj2.foo; - obj2.bar; - } - - // a construct signature with generics - interface BConstructor { - new (): B; - } - interface B { - foo: T; - } - declare var B: BConstructor; - - var obj3: B | string; - if (obj3 instanceof B) { // narrowed to B. - obj3.foo = 1; - obj3.foo = "str"; - ~~~~~~~~ -!!! error TS2322: Type 'string' is not assignable to type 'number'. - obj3.bar = "str"; - ~~~ -!!! error TS2339: Property 'bar' does not exist on type 'B'. - } - - var obj4: any; - if (obj4 instanceof B) { // can't type narrowing from any. - obj4.foo = "str"; - obj4.foo = 1; - obj4.bar = "str"; - } - - // has multiple construct signature - interface CConstructor { - new (value: string): C1; - new (value: number): C2; - } - interface C1 { - foo: string; - bar1: number; - } - interface C2 { - foo: string; - bar2: number; - } - declare var C: CConstructor; - - var obj5: C1 | A; - if (obj5 instanceof C) { // narrowed to C1. - obj5.foo; - obj5.bar1; - obj5.bar2; - ~~~~ -!!! error TS2339: Property 'bar2' does not exist on type 'C1'. - } - - var obj6: any; - if (obj6 instanceof C) { // can't type narrowing from any. - obj6.foo; - obj6.bar1; - obj6.bar2; - } - - // with object type literal - interface D { - foo: string; - } - declare var D: { new (): D; }; - - var obj7: D | string; - if (obj7 instanceof D) { // narrowed to D. - obj7.foo; - obj7.bar; - ~~~ -!!! error TS2339: Property 'bar' does not exist on type 'D'. - } - - var obj8: any; - if (obj8 instanceof D) { // can't type narrowing from any. - obj8.foo; - obj8.bar; - } - - // a construct signature that returns a union type - interface EConstructor { - new (): E1 | E2; - } - interface E1 { - foo: string; - bar1: number; - } - interface E2 { - foo: string; - bar2: number; - } - declare var E: EConstructor; - - var obj9: E1 | A; - if (obj9 instanceof E) { // narrowed to E1. - obj9.foo; - obj9.bar1; - obj9.bar2; - ~~~~ -!!! error TS2339: Property 'bar2' does not exist on type 'E1'. - } - - var obj10: any; - if (obj10 instanceof E) { // can't type narrowing from any. - obj10.foo; - obj10.bar1; - obj10.bar2; - } - - // a construct signature that returns any - interface FConstructor { - new (): any; - } - interface F { - foo: string; - bar: number; - } - declare var F: FConstructor; - - var obj11: F | string; - if (obj11 instanceof F) { // can't type narrowing, construct signiture returns any. - obj11.foo; - ~~~ -!!! error TS2339: Property 'foo' does not exist on type 'string | F'. - obj11.bar; - ~~~ -!!! error TS2339: Property 'bar' does not exist on type 'string | F'. - } - - var obj12: any; - if (obj12 instanceof F) { // can't type narrowing from any. - obj12.foo; - obj12.bar; - } - - // a type with a prototype, it overrides the construct signiture - interface GConstructor { - prototype: G1; // high priority - new (): G2; // low priority - } - interface G1 { - foo1: number; - } - interface G2 { - foo2: boolean; - } - declare var G: GConstructor; - - var obj13: G1 | G2; - if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype property. - obj13.foo1; - obj13.foo2; - ~~~~ -!!! error TS2339: Property 'foo2' does not exist on type 'G1'. - } - - var obj14: any; - if (obj14 instanceof G) { // can't type narrowing from any. - obj14.foo1; - obj14.foo2; - } - - // a type with a prototype that has any type - interface HConstructor { - prototype: any; // high priority, but any type is ignored. interface has implicit `prototype: any`. - new (): H; // low priority - } - interface H { - foo: number; - } - declare var H: HConstructor; - - var obj15: H | string; - if (obj15 instanceof H) { // narrowed to H. - obj15.foo; - obj15.bar; - ~~~ -!!! error TS2339: Property 'bar' does not exist on type 'H'. - } - - var obj16: any; - if (obj16 instanceof H) { // can't type narrowing from any. - obj16.foo1; - obj16.foo2; - } +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(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(63,10): error TS2339: Property 'bar2' does not exist on type 'C1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(82,10): error TS2339: Property 'bar' does not exist on type 'D'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(109,10): error TS2339: Property 'bar2' does not exist on type 'E1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(131,11): error TS2339: Property 'foo' does not exist on type 'string | F'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(132,11): error TS2339: Property 'bar' does not exist on type 'string | F'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(157,11): error TS2339: Property 'foo2' does not exist on type 'G1'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(179,11): error TS2339: Property 'bar' does not exist on type 'H'. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (10 errors) ==== + interface AConstructor { + new (): A; + } + interface A { + foo: string; + } + declare var A: AConstructor; + + var obj1: A | string; + if (obj1 instanceof A) { // narrowed to A. + obj1.foo; + obj1.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'A'. + } + + var obj2: any; + if (obj2 instanceof A) { // can't narrow type from 'any' + obj2.foo; + obj2.bar; + } + + // a construct signature with generics + interface BConstructor { + new (): B; + } + interface B { + foo: T; + } + declare var B: BConstructor; + + var obj3: B | string; + if (obj3 instanceof B) { // narrowed to B. + obj3.foo = 1; + obj3.foo = "str"; + ~~~~~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'number'. + obj3.bar = "str"; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'B'. + } + + var obj4: any; + if (obj4 instanceof B) { // can't narrow type from 'any' + obj4.foo = "str"; + obj4.foo = 1; + obj4.bar = "str"; + } + + // has multiple construct signature + interface CConstructor { + new (value: string): C1; + new (value: number): C2; + } + interface C1 { + foo: string; + bar1: number; + } + interface C2 { + foo: string; + bar2: number; + } + declare var C: CConstructor; + + var obj5: C1 | A; + if (obj5 instanceof C) { // narrowed to C1. + obj5.foo; + obj5.bar1; + obj5.bar2; + ~~~~ +!!! error TS2339: Property 'bar2' does not exist on type 'C1'. + } + + var obj6: any; + if (obj6 instanceof C) { // can't narrow type from 'any' + obj6.foo; + obj6.bar1; + obj6.bar2; + } + + // with object type literal + interface D { + foo: string; + } + declare var D: { new (): D; }; + + var obj7: D | string; + if (obj7 instanceof D) { // narrowed to D. + obj7.foo; + obj7.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'D'. + } + + var obj8: any; + if (obj8 instanceof D) { // can't narrow type from 'any' + obj8.foo; + obj8.bar; + } + + // a construct signature that returns a union type + interface EConstructor { + new (): E1 | E2; + } + interface E1 { + foo: string; + bar1: number; + } + interface E2 { + foo: string; + bar2: number; + } + declare var E: EConstructor; + + var obj9: E1 | A; + if (obj9 instanceof E) { // narrowed to E1. + obj9.foo; + obj9.bar1; + obj9.bar2; + ~~~~ +!!! error TS2339: Property 'bar2' does not exist on type 'E1'. + } + + var obj10: any; + if (obj10 instanceof E) { // can't narrow type from 'any' + obj10.foo; + obj10.bar1; + obj10.bar2; + } + + // a construct signature that returns any + interface FConstructor { + new (): any; + } + interface F { + foo: string; + bar: number; + } + declare var F: FConstructor; + + var obj11: F | string; + if (obj11 instanceof F) { // can't type narrowing, construct signature returns any. + obj11.foo; + ~~~ +!!! error TS2339: Property 'foo' does not exist on type 'string | F'. + obj11.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'string | F'. + } + + var obj12: any; + if (obj12 instanceof F) { // can't narrow type from 'any' + obj12.foo; + obj12.bar; + } + + // a type with a prototype, it overrides the construct signature + interface GConstructor { + prototype: G1; // high priority + new (): G2; // low priority + } + interface G1 { + foo1: number; + } + interface G2 { + foo2: boolean; + } + declare var G: GConstructor; + + var obj13: G1 | G2; + if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype property. + obj13.foo1; + obj13.foo2; + ~~~~ +!!! error TS2339: Property 'foo2' does not exist on type 'G1'. + } + + var obj14: any; + if (obj14 instanceof G) { // can't narrow type from 'any' + obj14.foo1; + obj14.foo2; + } + + // a type with a prototype that has any type + interface HConstructor { + prototype: any; // high priority, but any type is ignored. interface has implicit `prototype: any`. + new (): H; // low priority + } + interface H { + foo: number; + } + declare var H: HConstructor; + + var obj15: H | string; + if (obj15 instanceof H) { // narrowed to H. + obj15.foo; + obj15.bar; + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'H'. + } + + var obj16: any; + if (obj16 instanceof H) { // can't narrow type from 'any' + obj16.foo1; + obj16.foo2; + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js index 395a5e96e05..e5b12bacb1f 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.js @@ -1,4 +1,4 @@ -//// [typeGuardsWithInstanceOfByConstructorSignature.ts] +//// [typeGuardsWithInstanceOfByConstructorSignature.ts] interface AConstructor { new (): A; } @@ -14,7 +14,7 @@ if (obj1 instanceof A) { // narrowed to A. } var obj2: any; -if (obj2 instanceof A) { // can't type narrowing from any. +if (obj2 instanceof A) { // can't narrow type from 'any' obj2.foo; obj2.bar; } @@ -36,7 +36,7 @@ if (obj3 instanceof B) { // narrowed to B. } var obj4: any; -if (obj4 instanceof B) { // can't type narrowing from any. +if (obj4 instanceof B) { // can't narrow type from 'any' obj4.foo = "str"; obj4.foo = 1; obj4.bar = "str"; @@ -65,7 +65,7 @@ if (obj5 instanceof C) { // narrowed to C1. } var obj6: any; -if (obj6 instanceof C) { // can't type narrowing from any. +if (obj6 instanceof C) { // can't narrow type from 'any' obj6.foo; obj6.bar1; obj6.bar2; @@ -84,7 +84,7 @@ if (obj7 instanceof D) { // narrowed to D. } var obj8: any; -if (obj8 instanceof D) { // can't type narrowing from any. +if (obj8 instanceof D) { // can't narrow type from 'any' obj8.foo; obj8.bar; } @@ -111,7 +111,7 @@ if (obj9 instanceof E) { // narrowed to E1. } var obj10: any; -if (obj10 instanceof E) { // can't type narrowing from any. +if (obj10 instanceof E) { // can't narrow type from 'any' obj10.foo; obj10.bar1; obj10.bar2; @@ -128,18 +128,18 @@ interface F { declare var F: FConstructor; var obj11: F | string; -if (obj11 instanceof F) { // can't type narrowing, construct signiture returns any. +if (obj11 instanceof F) { // can't type narrowing, construct signature returns any. obj11.foo; obj11.bar; } var obj12: any; -if (obj12 instanceof F) { // can't type narrowing from any. +if (obj12 instanceof F) { // can't narrow type from 'any' obj12.foo; obj12.bar; } -// a type with a prototype, it overrides the construct signiture +// a type with a prototype, it overrides the construct signature interface GConstructor { prototype: G1; // high priority new (): G2; // low priority @@ -159,7 +159,7 @@ if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype prop } var obj14: any; -if (obj14 instanceof G) { // can't type narrowing from any. +if (obj14 instanceof G) { // can't narrow type from 'any' obj14.foo1; obj14.foo2; } @@ -181,96 +181,96 @@ if (obj15 instanceof H) { // narrowed to H. } var obj16: any; -if (obj16 instanceof H) { // can't type narrowing from any. - obj16.foo1; - obj16.foo2; -} - - -//// [typeGuardsWithInstanceOfByConstructorSignature.js] -var obj1; -if (obj1 instanceof A) { - obj1.foo; - obj1.bar; -} -var obj2; -if (obj2 instanceof A) { - obj2.foo; - obj2.bar; -} -var obj3; -if (obj3 instanceof B) { - obj3.foo = 1; - obj3.foo = "str"; - obj3.bar = "str"; -} -var obj4; -if (obj4 instanceof B) { - obj4.foo = "str"; - obj4.foo = 1; - obj4.bar = "str"; -} -var obj5; -if (obj5 instanceof C) { - obj5.foo; - obj5.bar1; - obj5.bar2; -} -var obj6; -if (obj6 instanceof C) { - obj6.foo; - obj6.bar1; - obj6.bar2; -} -var obj7; -if (obj7 instanceof D) { - obj7.foo; - obj7.bar; -} -var obj8; -if (obj8 instanceof D) { - obj8.foo; - obj8.bar; -} -var obj9; -if (obj9 instanceof E) { - obj9.foo; - obj9.bar1; - obj9.bar2; -} -var obj10; -if (obj10 instanceof E) { - obj10.foo; - obj10.bar1; - obj10.bar2; -} -var obj11; -if (obj11 instanceof F) { - obj11.foo; - obj11.bar; -} -var obj12; -if (obj12 instanceof F) { - obj12.foo; - obj12.bar; -} -var obj13; -if (obj13 instanceof G) { - obj13.foo1; - obj13.foo2; -} -var obj14; -if (obj14 instanceof G) { - obj14.foo1; - obj14.foo2; -} -var obj15; -if (obj15 instanceof H) { - obj15.foo; - obj15.bar; -} -var obj16; -if (obj16 instanceof H) { +if (obj16 instanceof H) { // can't narrow type from 'any' obj16.foo1; obj16.foo2; } + + +//// [typeGuardsWithInstanceOfByConstructorSignature.js] +var obj1; +if (obj1 instanceof A) { + obj1.foo; + obj1.bar; +} +var obj2; +if (obj2 instanceof A) { + obj2.foo; + obj2.bar; +} +var obj3; +if (obj3 instanceof B) { + obj3.foo = 1; + obj3.foo = "str"; + obj3.bar = "str"; +} +var obj4; +if (obj4 instanceof B) { + obj4.foo = "str"; + obj4.foo = 1; + obj4.bar = "str"; +} +var obj5; +if (obj5 instanceof C) { + obj5.foo; + obj5.bar1; + obj5.bar2; +} +var obj6; +if (obj6 instanceof C) { + obj6.foo; + obj6.bar1; + obj6.bar2; +} +var obj7; +if (obj7 instanceof D) { + obj7.foo; + obj7.bar; +} +var obj8; +if (obj8 instanceof D) { + obj8.foo; + obj8.bar; +} +var obj9; +if (obj9 instanceof E) { + obj9.foo; + obj9.bar1; + obj9.bar2; +} +var obj10; +if (obj10 instanceof E) { + obj10.foo; + obj10.bar1; + obj10.bar2; +} +var obj11; +if (obj11 instanceof F) { + obj11.foo; + obj11.bar; +} +var obj12; +if (obj12 instanceof F) { + obj12.foo; + obj12.bar; +} +var obj13; +if (obj13 instanceof G) { + obj13.foo1; + obj13.foo2; +} +var obj14; +if (obj14 instanceof G) { + obj14.foo1; + obj14.foo2; +} +var obj15; +if (obj15 instanceof H) { + obj15.foo; + obj15.bar; +} +var obj16; +if (obj16 instanceof H) { + obj16.foo1; + obj16.foo2; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts index c432ceb2bda..fee92ff10ca 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 type narrowing from any. +if (obj2 instanceof A) { // can't narrow type from 'any' obj2.foo; obj2.bar; } @@ -35,7 +35,7 @@ if (obj3 instanceof B) { // narrowed to B. } var obj4: any; -if (obj4 instanceof B) { // can't type narrowing from any. +if (obj4 instanceof B) { // can't narrow type from 'any' obj4.foo = "str"; obj4.foo = 1; obj4.bar = "str"; @@ -64,7 +64,7 @@ if (obj5 instanceof C) { // narrowed to C1. } var obj6: any; -if (obj6 instanceof C) { // can't type narrowing from any. +if (obj6 instanceof C) { // can't narrow type from 'any' obj6.foo; obj6.bar1; obj6.bar2; @@ -83,7 +83,7 @@ if (obj7 instanceof D) { // narrowed to D. } var obj8: any; -if (obj8 instanceof D) { // can't type narrowing from any. +if (obj8 instanceof D) { // can't narrow type from 'any' obj8.foo; obj8.bar; } @@ -110,7 +110,7 @@ if (obj9 instanceof E) { // narrowed to E1. } var obj10: any; -if (obj10 instanceof E) { // can't type narrowing from any. +if (obj10 instanceof E) { // can't narrow type from 'any' obj10.foo; obj10.bar1; obj10.bar2; @@ -127,18 +127,18 @@ interface F { declare var F: FConstructor; var obj11: F | string; -if (obj11 instanceof F) { // can't type narrowing, construct signiture returns any. +if (obj11 instanceof F) { // can't type narrowing, construct signature returns any. obj11.foo; obj11.bar; } var obj12: any; -if (obj12 instanceof F) { // can't type narrowing from any. +if (obj12 instanceof F) { // can't narrow type from 'any' obj12.foo; obj12.bar; } -// a type with a prototype, it overrides the construct signiture +// a type with a prototype, it overrides the construct signature interface GConstructor { prototype: G1; // high priority new (): G2; // low priority @@ -158,7 +158,7 @@ if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype prop } var obj14: any; -if (obj14 instanceof G) { // can't type narrowing from any. +if (obj14 instanceof G) { // can't narrow type from 'any' obj14.foo1; obj14.foo2; } @@ -180,7 +180,7 @@ if (obj15 instanceof H) { // narrowed to H. } var obj16: any; -if (obj16 instanceof H) { // can't type narrowing from any. +if (obj16 instanceof H) { // can't narrow type from 'any' obj16.foo1; obj16.foo2; }