Skip to content

Commit 55c3ec3

Browse files
committed
Fix decorator design:types emit for type variables.
Previously, TypeScript would resolve the reified types for the `design:types` decorator emit in the regular `currentScope`. That scope does not include class declaration bodies. However when reifying types, class declarations do introduce a new scope for any `TypeVariable`s declared on them. Because TS resolved the EntityName for such types against the parent scope (e.g. the source file), not the class scope, TypeScript would either fail to resolve the type (giving `TypeReferenceSerializationKind.Unknown`), or incorrectly resolve to a different, accidentally matching symbol in the outer scope (giving `TypeWithConstructSignatureAndValue`). This would result in an emit referencing an undeclared symbol, or mis-referencing the wrong symbol. __metadata("design:type", typeof (_a = typeof TypeVariable !== "undefined" && TypeVariable) === "function" && _a || Object) __metadata("design:type", TypeVariable) This change special cases `currentScope` for `serializeTypeReferenceNode` to use a class scope, if present. This changes the emit for a `TypeVariable` back to `Object`: __metadata("design:type", Object)
1 parent 22d33d2 commit 55c3ec3

16 files changed

+246
-1
lines changed

src/compiler/transformers/ts.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1969,7 +1969,16 @@ namespace ts {
19691969
* @param node The type reference node.
19701970
*/
19711971
function serializeTypeReferenceNode(node: TypeReferenceNode): SerializedTypeNode {
1972-
const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentScope);
1972+
// node might be a reference to type variable, which can be scoped to a class declaration, in addition to the regular
1973+
// TypeScript scopes. Walk up the AST to find the next class and use that as the lookup scope.
1974+
let scope: Node = node;
1975+
while (scope.parent && scope !== currentScope) {
1976+
scope = scope.parent;
1977+
if (isClassDeclaration(scope)) {
1978+
break;
1979+
}
1980+
}
1981+
const kind = resolver.getTypeReferenceSerializationKind(node.typeName, scope);
19731982
switch (kind) {
19741983
case TypeReferenceSerializationKind.Unknown:
19751984
const serialized = serializeEntityNameAsExpression(node.typeName, /*useFallback*/ true);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts(2,4): error TS2304: Cannot find name 'Decorate'.
2+
3+
4+
==== tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts (1 errors) ====
5+
export class C<TypeVariable> {
6+
@Decorate
7+
~~~~~~~~
8+
!!! error TS2304: Cannot find name 'Decorate'.
9+
member: TypeVariable;
10+
}
11+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [decoratorMetadataGenericTypeVariable.ts]
2+
export class C<TypeVariable> {
3+
@Decorate
4+
member: TypeVariable;
5+
}
6+
7+
8+
//// [decoratorMetadataGenericTypeVariable.js]
9+
"use strict";
10+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
11+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14+
return c > 3 && r && Object.defineProperty(target, key, r), r;
15+
};
16+
var __metadata = (this && this.__metadata) || function (k, v) {
17+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
18+
};
19+
exports.__esModule = true;
20+
var C = /** @class */ (function () {
21+
function C() {
22+
}
23+
__decorate([
24+
Decorate,
25+
__metadata("design:type", Object)
26+
], C.prototype, "member");
27+
return C;
28+
}());
29+
exports.C = C;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts ===
2+
export class C<TypeVariable> {
3+
>C : Symbol(C, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 0))
4+
>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 15))
5+
6+
@Decorate
7+
member: TypeVariable;
8+
>member : Symbol(C.member, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 30))
9+
>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 15))
10+
}
11+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts ===
2+
export class C<TypeVariable> {
3+
>C : C<TypeVariable>
4+
>TypeVariable : TypeVariable
5+
6+
@Decorate
7+
>Decorate : any
8+
9+
member: TypeVariable;
10+
>member : TypeVariable
11+
>TypeVariable : TypeVariable
12+
}
13+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts(2,4): error TS2304: Cannot find name 'Decorate'.
2+
3+
4+
==== tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts (1 errors) ====
5+
export class C<TypeVariable = string> {
6+
@Decorate
7+
~~~~~~~~
8+
!!! error TS2304: Cannot find name 'Decorate'.
9+
member: TypeVariable;
10+
}
11+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [decoratorMetadataGenericTypeVariableDefault.ts]
2+
export class C<TypeVariable = string> {
3+
@Decorate
4+
member: TypeVariable;
5+
}
6+
7+
8+
//// [decoratorMetadataGenericTypeVariableDefault.js]
9+
"use strict";
10+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
11+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14+
return c > 3 && r && Object.defineProperty(target, key, r), r;
15+
};
16+
var __metadata = (this && this.__metadata) || function (k, v) {
17+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
18+
};
19+
exports.__esModule = true;
20+
var C = /** @class */ (function () {
21+
function C() {
22+
}
23+
__decorate([
24+
Decorate,
25+
__metadata("design:type", Object)
26+
], C.prototype, "member");
27+
return C;
28+
}());
29+
exports.C = C;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts ===
2+
export class C<TypeVariable = string> {
3+
>C : Symbol(C, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 0))
4+
>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 15))
5+
6+
@Decorate
7+
member: TypeVariable;
8+
>member : Symbol(C.member, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 39))
9+
>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 15))
10+
}
11+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts ===
2+
export class C<TypeVariable = string> {
3+
>C : C<TypeVariable>
4+
>TypeVariable : TypeVariable
5+
6+
@Decorate
7+
>Decorate : any
8+
9+
member: TypeVariable;
10+
>member : TypeVariable
11+
>TypeVariable : TypeVariable
12+
}
13+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts(5,4): error TS2304: Cannot find name 'Decorate'.
2+
3+
4+
==== tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts (1 errors) ====
5+
// Unused, but could collide with the named type argument below.
6+
class TypeVariable {}
7+
8+
export class C<TypeVariable> {
9+
@Decorate
10+
~~~~~~~~
11+
!!! error TS2304: Cannot find name 'Decorate'.
12+
member: TypeVariable;
13+
}
14+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//// [decoratorMetadataGenericTypeVariableInScope.ts]
2+
// Unused, but could collide with the named type argument below.
3+
class TypeVariable {}
4+
5+
export class C<TypeVariable> {
6+
@Decorate
7+
member: TypeVariable;
8+
}
9+
10+
11+
//// [decoratorMetadataGenericTypeVariableInScope.js]
12+
"use strict";
13+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
14+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
15+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
16+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
17+
return c > 3 && r && Object.defineProperty(target, key, r), r;
18+
};
19+
var __metadata = (this && this.__metadata) || function (k, v) {
20+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
21+
};
22+
exports.__esModule = true;
23+
// Unused, but could collide with the named type argument below.
24+
var TypeVariable = /** @class */ (function () {
25+
function TypeVariable() {
26+
}
27+
return TypeVariable;
28+
}());
29+
var C = /** @class */ (function () {
30+
function C() {
31+
}
32+
__decorate([
33+
Decorate,
34+
__metadata("design:type", Object)
35+
], C.prototype, "member");
36+
return C;
37+
}());
38+
exports.C = C;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts ===
2+
// Unused, but could collide with the named type argument below.
3+
class TypeVariable {}
4+
>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 0, 0))
5+
6+
export class C<TypeVariable> {
7+
>C : Symbol(C, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 1, 21))
8+
>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 3, 15))
9+
10+
@Decorate
11+
member: TypeVariable;
12+
>member : Symbol(C.member, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 3, 30))
13+
>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 3, 15))
14+
}
15+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts ===
2+
// Unused, but could collide with the named type argument below.
3+
class TypeVariable {}
4+
>TypeVariable : TypeVariable
5+
6+
export class C<TypeVariable> {
7+
>C : C<TypeVariable>
8+
>TypeVariable : TypeVariable
9+
10+
@Decorate
11+
>Decorate : any
12+
13+
member: TypeVariable;
14+
>member : TypeVariable
15+
>TypeVariable : TypeVariable
16+
}
17+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @experimentalDecorators: true
2+
// @emitDecoratorMetadata: true
3+
4+
export class C<TypeVariable> {
5+
@Decorate
6+
member: TypeVariable;
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @experimentalDecorators: true
2+
// @emitDecoratorMetadata: true
3+
4+
export class C<TypeVariable = string> {
5+
@Decorate
6+
member: TypeVariable;
7+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @experimentalDecorators: true
2+
// @emitDecoratorMetadata: true
3+
4+
// Unused, but could collide with the named type argument below.
5+
class TypeVariable {}
6+
7+
export class C<TypeVariable> {
8+
@Decorate
9+
member: TypeVariable;
10+
}

0 commit comments

Comments
 (0)