Skip to content

Commit ab10d50

Browse files
committed
support instantiate signature, it has type parameters.
1 parent 35d6e98 commit ab10d50

File tree

4 files changed

+380
-35
lines changed

4 files changed

+380
-35
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5365,25 +5365,25 @@ module ts {
53655365
}
53665366
}
53675367
// Target type is type of constructor signiture
5368-
let constructorSignitures: Signature[];
5368+
let constructSignitures: Signature[];
53695369
if (rightType.flags & TypeFlags.Interface) {
5370-
constructorSignitures = (<InterfaceTypeWithDeclaredMembers>rightType).declaredConstructSignatures;
5370+
constructSignitures = (<InterfaceTypeWithDeclaredMembers>rightType).declaredConstructSignatures;
53715371
}
53725372
if (rightType.flags & TypeFlags.Anonymous) {
5373-
constructorSignitures = (<ResolvedType>rightType).constructSignatures;
5373+
constructSignitures = (<ResolvedType>rightType).constructSignatures;
53745374
}
5375-
if (constructorSignitures) {
5376-
let constructorType = getUnionType(map(constructorSignitures, constructorSignature => {
5377-
if (constructorSignature.typeParameters && constructorSignature.typeParameters.length !== 0) {
5378-
// TODO convert type parameters to any or empty object types. e.g. Sample<T> -> Sample<any> or Sample<{}>.
5375+
if (constructSignitures) {
5376+
let instanceType = getUnionType(map(constructSignitures, constructSignature => {
5377+
if (constructSignature.typeParameters && constructSignature.typeParameters.length !== 0) {
5378+
constructSignature = instantiateSignature(constructSignature, createTypeMapper(constructSignature.typeParameters, map(constructSignature.typeParameters, _ => anyType)), true)
53795379
}
5380-
return constructorSignature.resolvedReturnType;
5380+
return constructSignature.resolvedReturnType;
53815381
}));
53825382
// Pickup type from union types
53835383
if (type.flags & TypeFlags.Union) {
5384-
return getUnionType(filter((<UnionType>type).types, t => isTypeSubtypeOf(t, constructorType)));
5384+
return getUnionType(filter((<UnionType>type).types, t => isTypeSubtypeOf(t, instanceType)));
53855385
}
5386-
return constructorType;
5386+
return instanceType;
53875387
}
53885388
return type;
53895389
}

tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt

Lines changed: 123 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(12,10): error TS2339: Property 'bar' does not exist on type 'A'.
2-
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(32,10): error TS2339: Property 'foo' does not exist on type '{}'.
3-
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(33,10): error TS2339: Property 'foo' does not exist on type '{}'.
4-
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(34,10): error TS2339: Property 'bar' does not exist on type '{}'.
2+
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(33,5): error TS2322: Type 'string' is not assignable to type 'number'.
3+
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(34,10): error TS2339: Property 'bar' does not exist on type 'B<number>'.
54
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(63,10): error TS2339: Property 'bar2' does not exist on type 'C1'.
65
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(82,10): error TS2339: Property 'bar' does not exist on type 'D'.
6+
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(109,10): error TS2339: Property 'bar2' does not exist on type 'E1'.
7+
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(131,11): error TS2339: Property 'foo' does not exist on type 'string | F'.
8+
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(132,11): error TS2339: Property 'bar' does not exist on type 'string | F'.
9+
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(157,11): error TS2339: Property 'foo2' does not exist on type 'G1'.
10+
tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(179,11): error TS2339: Property 'bar' does not exist on type 'H'.
711

812

9-
==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (6 errors) ====
13+
==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (10 errors) ====
1014
interface AConstructor {
1115
new (): A;
1216
}
@@ -29,7 +33,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
2933
obj2.bar;
3034
}
3135

32-
// with generics
36+
// a construct signature with generics
3337
interface BConstructor {
3438
new <T>(): B<T>;
3539
}
@@ -38,17 +42,15 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
3842
}
3943
declare var B: BConstructor;
4044

41-
var obj3: B<string> | A;
42-
if (obj3 instanceof B) { // narrowed to B<string>.
43-
obj3.foo = "str";
44-
~~~
45-
!!! error TS2339: Property 'foo' does not exist on type '{}'.
45+
var obj3: B<number> | string;
46+
if (obj3 instanceof B) { // narrowed to B<number>.
4647
obj3.foo = 1;
47-
~~~
48-
!!! error TS2339: Property 'foo' does not exist on type '{}'.
48+
obj3.foo = "str";
49+
~~~~~~~~
50+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
4951
obj3.bar = "str";
5052
~~~
51-
!!! error TS2339: Property 'bar' does not exist on type '{}'.
53+
!!! error TS2339: Property 'bar' does not exist on type 'B<number>'.
5254
}
5355

5456
var obj4: any;
@@ -58,7 +60,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
5860
obj4.bar = "str";
5961
}
6062

61-
// has multiple constructor signature
63+
// has multiple construct signature
6264
interface CConstructor {
6365
new (value: string): C1;
6466
new (value: number): C2;
@@ -108,4 +110,111 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru
108110
obj8.foo;
109111
obj8.bar;
110112
}
113+
114+
// a construct signature that returns a union type
115+
interface EConstructor {
116+
new (): E1 | E2;
117+
}
118+
interface E1 {
119+
foo: string;
120+
bar1: number;
121+
}
122+
interface E2 {
123+
foo: string;
124+
bar2: number;
125+
}
126+
declare var E: EConstructor;
127+
128+
var obj9: E1 | A;
129+
if (obj9 instanceof E) { // narrowed to E1.
130+
obj9.foo;
131+
obj9.bar1;
132+
obj9.bar2;
133+
~~~~
134+
!!! error TS2339: Property 'bar2' does not exist on type 'E1'.
135+
}
136+
137+
var obj10: any;
138+
if (obj10 instanceof E) { // can't type narrowing from any.
139+
obj10.foo;
140+
obj10.bar1;
141+
obj10.bar2;
142+
}
143+
144+
// a construct signature that returns any
145+
interface FConstructor {
146+
new (): any;
147+
}
148+
interface F {
149+
foo: string;
150+
bar: number;
151+
}
152+
declare var F: FConstructor;
153+
154+
var obj11: F | string;
155+
if (obj11 instanceof F) { // can't type narrowing, construct signiture returns any.
156+
obj11.foo;
157+
~~~
158+
!!! error TS2339: Property 'foo' does not exist on type 'string | F'.
159+
obj11.bar;
160+
~~~
161+
!!! error TS2339: Property 'bar' does not exist on type 'string | F'.
162+
}
163+
164+
var obj12: any;
165+
if (obj12 instanceof F) { // can't type narrowing from any.
166+
obj12.foo;
167+
obj12.bar;
168+
}
169+
170+
// a type with a prototype, it overrides the construct signiture
171+
interface GConstructor {
172+
prototype: G1; // high priority
173+
new (): G2; // low priority
174+
}
175+
interface G1 {
176+
foo1: number;
177+
}
178+
interface G2 {
179+
foo2: boolean;
180+
}
181+
declare var G: GConstructor;
182+
183+
var obj13: G1 | G2;
184+
if (obj13 instanceof G) { // narrowed to G1. G1 is return type of prototype property.
185+
obj13.foo1;
186+
obj13.foo2;
187+
~~~~
188+
!!! error TS2339: Property 'foo2' does not exist on type 'G1'.
189+
}
190+
191+
var obj14: any;
192+
if (obj14 instanceof G) { // can't type narrowing from any.
193+
obj14.foo1;
194+
obj14.foo2;
195+
}
196+
197+
// a type with a prototype that has any type
198+
interface HConstructor {
199+
prototype: any; // high priority, but any type is ignored. interface has implicit `prototype: any`.
200+
new (): H; // low priority
201+
}
202+
interface H {
203+
foo: number;
204+
}
205+
declare var H: HConstructor;
206+
207+
var obj15: H | string;
208+
if (obj15 instanceof H) { // narrowed to H.
209+
obj15.foo;
210+
obj15.bar;
211+
~~~
212+
!!! error TS2339: Property 'bar' does not exist on type 'H'.
213+
}
214+
215+
var obj16: any;
216+
if (obj16 instanceof H) { // can't type narrowing from any.
217+
obj16.foo1;
218+
obj16.foo2;
219+
}
111220

0 commit comments

Comments
 (0)