Skip to content

Commit bb4aa2c

Browse files
committed
Merge pull request microsoft#3899 from Microsoft/fixTypeResolutionInTypeSerialization
Fix emit for decorator type metadata.
2 parents 4816bb5 + 8ea1a22 commit bb4aa2c

File tree

8 files changed

+143
-9
lines changed

8 files changed

+143
-9
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14351,15 +14351,17 @@ namespace ts {
1435114351
return type.flags & TypeFlags.ObjectType && getSignaturesOfType(type, SignatureKind.Call).length > 0;
1435214352
}
1435314353

14354-
function getTypeReferenceSerializationKind(node: TypeReferenceNode): TypeReferenceSerializationKind {
14354+
function getTypeReferenceSerializationKind(typeName: EntityName): TypeReferenceSerializationKind {
1435514355
// Resolve the symbol as a value to ensure the type can be reached at runtime during emit.
14356-
let symbol = resolveEntityName(node.typeName, SymbolFlags.Value, /*ignoreErrors*/ true);
14357-
let constructorType = symbol ? getTypeOfSymbol(symbol) : undefined;
14356+
let valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true);
14357+
let constructorType = valueSymbol ? getTypeOfSymbol(valueSymbol) : undefined;
1435814358
if (constructorType && isConstructorType(constructorType)) {
1435914359
return TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue;
1436014360
}
1436114361

14362-
let type = getTypeFromTypeNode(node);
14362+
// Resolve the symbol as a type so that we can provide a more useful hint for the type serializer.
14363+
let typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true);
14364+
let type = getDeclaredTypeOfSymbol(typeSymbol);
1436314365
if (type === unknownType) {
1436414366
return TypeReferenceSerializationKind.Unknown;
1436514367
}

src/compiler/emitter.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4945,8 +4945,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
49454945

49464946
/** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */
49474947
function emitSerializedTypeReferenceNode(node: TypeReferenceNode) {
4948-
let typeName = node.typeName;
4949-
let result = resolver.getTypeReferenceSerializationKind(node);
4948+
let location: Node = node.parent;
4949+
while (isDeclaration(location) || isTypeNode(location)) {
4950+
location = location.parent;
4951+
}
4952+
4953+
// Clone the type name and parent it to a location outside of the current declaration.
4954+
let typeName = cloneEntityName(node.typeName);
4955+
typeName.parent = location;
4956+
4957+
let result = resolver.getTypeReferenceSerializationKind(typeName);
49504958
switch (result) {
49514959
case TypeReferenceSerializationKind.Unknown:
49524960
let temp = createAndRecordTempVariable(TempFlags.Auto);
@@ -5078,6 +5086,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
50785086
argumentsWritten++;
50795087
}
50805088
if (shouldEmitParamTypesMetadata(node)) {
5089+
debugger;
50815090
if (writeComma || argumentsWritten) {
50825091
write(", ");
50835092
}

src/compiler/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,7 +1578,7 @@ namespace ts {
15781578
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
15791579
getBlockScopedVariableId(node: Identifier): number;
15801580
getReferencedValueDeclaration(reference: Identifier): Declaration;
1581-
getTypeReferenceSerializationKind(node: TypeReferenceNode): TypeReferenceSerializationKind;
1581+
getTypeReferenceSerializationKind(typeName: EntityName): TypeReferenceSerializationKind;
15821582
isOptionalParameter(node: ParameterDeclaration): boolean;
15831583
}
15841584

@@ -1786,10 +1786,10 @@ namespace ts {
17861786
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
17871787
UnionOrIntersection = Union | Intersection,
17881788
StructuredType = ObjectType | Union | Intersection,
1789-
/* @internal */
1789+
/* @internal */
17901790
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral,
17911791
/* @internal */
1792-
PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType
1792+
PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType
17931793
}
17941794

17951795
// Properties common to all types

src/compiler/utilities.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,22 @@ namespace ts {
14221422
return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile;
14231423
}
14241424

1425+
export function cloneEntityName(node: EntityName): EntityName {
1426+
if (node.kind === SyntaxKind.Identifier) {
1427+
let clone = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
1428+
clone.text = (<Identifier>node).text;
1429+
return clone;
1430+
}
1431+
else {
1432+
let clone = <QualifiedName>createSynthesizedNode(SyntaxKind.QualifiedName);
1433+
clone.left = cloneEntityName((<QualifiedName>node).left);
1434+
clone.left.parent = clone;
1435+
clone.right = <Identifier>cloneEntityName((<QualifiedName>node).right);
1436+
clone.right.parent = clone;
1437+
return clone;
1438+
}
1439+
}
1440+
14251441
export function nodeIsSynthesized(node: Node): boolean {
14261442
return node.pos === -1;
14271443
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//// [tests/cases/conformance/decorators/decoratorMetadata.ts] ////
2+
3+
//// [service.ts]
4+
export default class Service {
5+
}
6+
//// [component.ts]
7+
import Service from "./service";
8+
9+
declare var decorator: any;
10+
11+
@decorator
12+
class MyComponent {
13+
constructor(public Service: Service) {
14+
}
15+
}
16+
17+
//// [service.js]
18+
var Service = (function () {
19+
function Service() {
20+
}
21+
return Service;
22+
})();
23+
Object.defineProperty(exports, "__esModule", { value: true });
24+
exports.default = Service;
25+
//// [component.js]
26+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
27+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
28+
switch (arguments.length) {
29+
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
30+
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
31+
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
32+
}
33+
};
34+
var __metadata = (this && this.__metadata) || function (k, v) {
35+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
36+
};
37+
var MyComponent = (function () {
38+
function MyComponent(Service) {
39+
this.Service = Service;
40+
}
41+
MyComponent = __decorate([
42+
decorator,
43+
__metadata('design:paramtypes', [service_1.default])
44+
], MyComponent);
45+
return MyComponent;
46+
})();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/decorators/service.ts ===
2+
export default class Service {
3+
>Service : Symbol(Service, Decl(service.ts, 0, 0))
4+
}
5+
=== tests/cases/conformance/decorators/component.ts ===
6+
import Service from "./service";
7+
>Service : Symbol(Service, Decl(component.ts, 0, 6))
8+
9+
declare var decorator: any;
10+
>decorator : Symbol(decorator, Decl(component.ts, 2, 11))
11+
12+
@decorator
13+
>decorator : Symbol(decorator, Decl(component.ts, 2, 11))
14+
15+
class MyComponent {
16+
>MyComponent : Symbol(MyComponent, Decl(component.ts, 2, 27))
17+
18+
constructor(public Service: Service) {
19+
>Service : Symbol(Service, Decl(component.ts, 6, 16))
20+
>Service : Symbol(Service, Decl(component.ts, 0, 6))
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/decorators/service.ts ===
2+
export default class Service {
3+
>Service : Service
4+
}
5+
=== tests/cases/conformance/decorators/component.ts ===
6+
import Service from "./service";
7+
>Service : typeof Service
8+
9+
declare var decorator: any;
10+
>decorator : any
11+
12+
@decorator
13+
>decorator : any
14+
15+
class MyComponent {
16+
>MyComponent : MyComponent
17+
18+
constructor(public Service: Service) {
19+
>Service : Service
20+
>Service : Service
21+
}
22+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @experimentalDecorators: true
2+
// @emitDecoratorMetadata: true
3+
// @target: es5
4+
// @module: commonjs
5+
// @filename: service.ts
6+
export default class Service {
7+
}
8+
// @filename: component.ts
9+
import Service from "./service";
10+
11+
declare var decorator: any;
12+
13+
@decorator
14+
class MyComponent {
15+
constructor(public Service: Service) {
16+
}
17+
}

0 commit comments

Comments
 (0)