Fixes an issue when resolving a type name as an expression when emitting type metadata for decorators

This commit is contained in:
Ron Buckton 2015-07-16 15:13:31 -07:00
parent 81711f9388
commit b620cace92
8 changed files with 140 additions and 7 deletions

View File

@ -14016,15 +14016,17 @@ namespace ts {
return type.flags & TypeFlags.ObjectType && getSignaturesOfType(type, SignatureKind.Call).length > 0;
}
function getTypeReferenceSerializationKind(node: TypeReferenceNode): TypeReferenceSerializationKind {
function getTypeReferenceSerializationKind(typeName: EntityName): TypeReferenceSerializationKind {
// Resolve the symbol as a value to ensure the type can be reached at runtime during emit.
let symbol = resolveEntityName(node.typeName, SymbolFlags.Value, /*ignoreErrors*/ true);
let constructorType = symbol ? getTypeOfSymbol(symbol) : undefined;
let valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true);
let constructorType = valueSymbol ? getTypeOfSymbol(valueSymbol) : undefined;
if (constructorType && isConstructorType(constructorType)) {
return TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue;
}
let type = getTypeFromTypeNode(node);
// Resolve the symbol as a type so that we can provide a more useful hint for the type serializer.
let typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true);
let type = getDeclaredTypeOfSymbol(typeSymbol);
if (type === unknownType) {
return TypeReferenceSerializationKind.Unknown;
}

View File

@ -4897,8 +4897,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
/** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */
function emitSerializedTypeReferenceNode(node: TypeReferenceNode) {
let typeName = node.typeName;
let result = resolver.getTypeReferenceSerializationKind(node);
let location: Node = node.parent;
while (isDeclaration(location) || isTypeNode(location)) {
location = location.parent;
}
// Clone the type name and parent it to a location outside of the current declaration.
let typeName = cloneEntityName(node.typeName);
typeName.parent = location;
let result = resolver.getTypeReferenceSerializationKind(typeName);
switch (result) {
case TypeReferenceSerializationKind.Unknown:
let temp = createAndRecordTempVariable(TempFlags.Auto);
@ -5030,6 +5038,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
argumentsWritten++;
}
if (shouldEmitParamTypesMetadata(node)) {
debugger;
if (writeComma || argumentsWritten) {
write(", ");
}

View File

@ -1573,7 +1573,7 @@ namespace ts {
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
getBlockScopedVariableId(node: Identifier): number;
getReferencedValueDeclaration(reference: Identifier): Declaration;
getTypeReferenceSerializationKind(node: TypeReferenceNode): TypeReferenceSerializationKind;
getTypeReferenceSerializationKind(typeName: EntityName): TypeReferenceSerializationKind;
}
export const enum SymbolFlags {

View File

@ -1424,6 +1424,22 @@ namespace ts {
return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile;
}
export function cloneEntityName(node: EntityName): EntityName {
if (node.kind === SyntaxKind.Identifier) {
let clone = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
clone.text = (<Identifier>node).text;
return clone;
}
else {
let clone = <QualifiedName>createSynthesizedNode(SyntaxKind.QualifiedName);
clone.left = cloneEntityName((<QualifiedName>node).left);
clone.left.parent = clone;
clone.right = <Identifier>cloneEntityName((<QualifiedName>node).right);
clone.right.parent = clone;
return clone;
}
}
export function nodeIsSynthesized(node: Node): boolean {
return node.pos === -1;
}

View File

@ -0,0 +1,45 @@
//// [tests/cases/conformance/decorators/decoratorMetadata.ts] ////
//// [service.ts]
export default class Service {
}
//// [component.ts]
import Service from "./service";
declare var decorator: any;
@decorator
class MyComponent {
constructor(public Service: Service) {
}
}
//// [service.js]
var Service = (function () {
function Service() {
}
return Service;
})();
exports.default = Service;
//// [component.js]
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var MyComponent = (function () {
function MyComponent(Service) {
this.Service = Service;
}
MyComponent = __decorate([
decorator,
__metadata('design:paramtypes', [service_1.default])
], MyComponent);
return MyComponent;
})();

View File

@ -0,0 +1,22 @@
=== tests/cases/conformance/decorators/service.ts ===
export default class Service {
>Service : Symbol(Service, Decl(service.ts, 0, 0))
}
=== tests/cases/conformance/decorators/component.ts ===
import Service from "./service";
>Service : Symbol(Service, Decl(component.ts, 0, 6))
declare var decorator: any;
>decorator : Symbol(decorator, Decl(component.ts, 2, 11))
@decorator
>decorator : Symbol(decorator, Decl(component.ts, 2, 11))
class MyComponent {
>MyComponent : Symbol(MyComponent, Decl(component.ts, 2, 27))
constructor(public Service: Service) {
>Service : Symbol(Service, Decl(component.ts, 6, 16))
>Service : Symbol(Service, Decl(component.ts, 0, 6))
}
}

View File

@ -0,0 +1,22 @@
=== tests/cases/conformance/decorators/service.ts ===
export default class Service {
>Service : Service
}
=== tests/cases/conformance/decorators/component.ts ===
import Service from "./service";
>Service : typeof Service
declare var decorator: any;
>decorator : any
@decorator
>decorator : any
class MyComponent {
>MyComponent : MyComponent
constructor(public Service: Service) {
>Service : Service
>Service : Service
}
}

View File

@ -0,0 +1,17 @@
// @experimentalDecorators: true
// @emitDecoratorMetadata: true
// @target: es5
// @module: commonjs
// @filename: service.ts
export default class Service {
}
// @filename: component.ts
import Service from "./service";
declare var decorator: any;
@decorator
class MyComponent {
constructor(public Service: Service) {
}
}