Skip to content

Commit 9d6dc36

Browse files
committed
Merge pull request #3798 from Microsoft/typeArgumentInferenceClassExpressions
Type argument inference for class expressions
2 parents 6c4dc28 + 8bb956e commit 9d6dc36

12 files changed

+185
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5503,7 +5503,7 @@ namespace ts {
55035503
}
55045504
}
55055505
else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) ||
5506-
(target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) {
5506+
(target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class))) {
55075507
// If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members
55085508
if (isInProcess(source, target)) {
55095509
return;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [typeArgumentInferenceWithClassExpression1.ts]
2+
function foo<T>(x = class { static prop: T }): T {
3+
return undefined;
4+
}
5+
6+
foo(class { static prop = "hello" }).length;
7+
8+
//// [typeArgumentInferenceWithClassExpression1.js]
9+
function foo(x) {
10+
if (x === void 0) { x = (function () {
11+
function class_1() {
12+
}
13+
return class_1;
14+
})(); }
15+
return undefined;
16+
}
17+
foo((function () {
18+
function class_2() {
19+
}
20+
class_2.prop = "hello";
21+
return class_2;
22+
})()).length;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression1.ts ===
2+
function foo<T>(x = class { static prop: T }): T {
3+
>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 0))
4+
>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 13))
5+
>x : Symbol(x, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 16))
6+
>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 27))
7+
>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 13))
8+
>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 13))
9+
10+
return undefined;
11+
>undefined : Symbol(undefined)
12+
}
13+
14+
foo(class { static prop = "hello" }).length;
15+
>foo(class { static prop = "hello" }).length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
16+
>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 0))
17+
>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression1.ts, 4, 11))
18+
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
19+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression1.ts ===
2+
function foo<T>(x = class { static prop: T }): T {
3+
>foo : <T>(x?: typeof (Anonymous class)) => T
4+
>T : T
5+
>x : typeof (Anonymous class)
6+
>class { static prop: T } : typeof (Anonymous class)
7+
>prop : T
8+
>T : T
9+
>T : T
10+
11+
return undefined;
12+
>undefined : undefined
13+
}
14+
15+
foo(class { static prop = "hello" }).length;
16+
>foo(class { static prop = "hello" }).length : number
17+
>foo(class { static prop = "hello" }) : string
18+
>foo : <T>(x?: typeof (Anonymous class)) => T
19+
>class { static prop = "hello" } : typeof (Anonymous class)
20+
>prop : string
21+
>"hello" : string
22+
>length : number
23+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts(6,5): error TS2345: Argument of type 'typeof (Anonymous class)' is not assignable to parameter of type 'typeof (Anonymous class)'.
2+
Type '(Anonymous class)' is not assignable to type 'foo<{}>.'.
3+
Property 'prop' is missing in type '(Anonymous class)'.
4+
5+
6+
==== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts (1 errors) ====
7+
function foo<T>(x = class { prop: T }): T {
8+
return undefined;
9+
}
10+
11+
// Should not infer string because it is a static property
12+
foo(class { static prop = "hello" }).length;
13+
~~~~~
14+
!!! error TS2345: Argument of type 'typeof (Anonymous class)' is not assignable to parameter of type 'typeof (Anonymous class)'.
15+
!!! error TS2345: Type '(Anonymous class)' is not assignable to type 'foo<{}>.'.
16+
!!! error TS2345: Property 'prop' is missing in type '(Anonymous class)'.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [typeArgumentInferenceWithClassExpression2.ts]
2+
function foo<T>(x = class { prop: T }): T {
3+
return undefined;
4+
}
5+
6+
// Should not infer string because it is a static property
7+
foo(class { static prop = "hello" }).length;
8+
9+
//// [typeArgumentInferenceWithClassExpression2.js]
10+
function foo(x) {
11+
if (x === void 0) { x = (function () {
12+
function class_1() {
13+
}
14+
return class_1;
15+
})(); }
16+
return undefined;
17+
}
18+
// Should not infer string because it is a static property
19+
foo((function () {
20+
function class_2() {
21+
}
22+
class_2.prop = "hello";
23+
return class_2;
24+
})()).length;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [typeArgumentInferenceWithClassExpression3.ts]
2+
function foo<T>(x = class { prop: T }): T {
3+
return undefined;
4+
}
5+
6+
foo(class { prop = "hello" }).length;
7+
8+
//// [typeArgumentInferenceWithClassExpression3.js]
9+
function foo(x) {
10+
if (x === void 0) { x = (function () {
11+
function class_1() {
12+
}
13+
return class_1;
14+
})(); }
15+
return undefined;
16+
}
17+
foo((function () {
18+
function class_2() {
19+
this.prop = "hello";
20+
}
21+
return class_2;
22+
})()).length;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts ===
2+
function foo<T>(x = class { prop: T }): T {
3+
>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 0))
4+
>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 13))
5+
>x : Symbol(x, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 16))
6+
>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 27))
7+
>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 13))
8+
>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 13))
9+
10+
return undefined;
11+
>undefined : Symbol(undefined)
12+
}
13+
14+
foo(class { prop = "hello" }).length;
15+
>foo(class { prop = "hello" }).length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
16+
>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 0))
17+
>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression3.ts, 4, 11))
18+
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
19+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts ===
2+
function foo<T>(x = class { prop: T }): T {
3+
>foo : <T>(x?: typeof (Anonymous class)) => T
4+
>T : T
5+
>x : typeof (Anonymous class)
6+
>class { prop: T } : typeof (Anonymous class)
7+
>prop : T
8+
>T : T
9+
>T : T
10+
11+
return undefined;
12+
>undefined : undefined
13+
}
14+
15+
foo(class { prop = "hello" }).length;
16+
>foo(class { prop = "hello" }).length : number
17+
>foo(class { prop = "hello" }) : string
18+
>foo : <T>(x?: typeof (Anonymous class)) => T
19+
>class { prop = "hello" } : typeof (Anonymous class)
20+
>prop : string
21+
>"hello" : string
22+
>length : number
23+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function foo<T>(x = class { static prop: T }): T {
2+
return undefined;
3+
}
4+
5+
foo(class { static prop = "hello" }).length;

0 commit comments

Comments
 (0)