diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e67c6f3146f..344dd35a5c3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16854,6 +16854,11 @@ namespace ts { function isValueAliasDeclaration(node: Node): boolean { node = getSourceTreeNode(node); + if (node === undefined) { + // A synthesized node comes from an emit transformation and is always a value. + return true; + } + switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ImportClause: diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index e0508266818..6094dcbb2d6 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -735,15 +735,7 @@ namespace ts { const classDecl = original as ClassDeclaration; if (classDecl.name) { const statements = [node]; - // Avoid emitting a default because a decorated default-exported class will have been rewritten in the TS transformer to - // a decorator assignment (`foo = __decorate(...)`) followed by a separate default export declaration (`export default foo`). - // We will eventually take care of that default export assignment when we transform the generated default export declaration. - if (hasModifier(classDecl, ModifierFlags.Export) && !hasModifier(classDecl, ModifierFlags.Default)) { - addExportMemberAssignment(statements, classDecl) - } - addExportMemberAssignments(statements, classDecl.name); - return statements; } } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 8ff758a4206..c1d119b2487 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -420,6 +420,26 @@ namespace ts { } } + /** + * Tests whether we should emit a __decorate call for a class declaration. + */ + function shouldEmitDecorateCallForClass(node: ClassDeclaration) { + if (node.decorators && node.decorators.length > 0) { + return true; + } + + const constructor = getFirstConstructorWithBody(node); + if (constructor) { + for (const parameter of constructor.parameters) { + if (parameter.decorators && parameter.decorators.length > 0) { + return true; + } + } + } + + return false; + } + /** * Transforms a class declaration with TypeScript syntax into compatible ES6. * @@ -434,6 +454,7 @@ namespace ts { function visitClassDeclaration(node: ClassDeclaration): VisitResult { const staticProperties = getInitializedProperties(node, /*isStatic*/ true); const hasExtendsClause = getClassExtendsHeritageClauseElement(node) !== undefined; + const isDecoratedClass = shouldEmitDecorateCallForClass(node); let decoratedClassAlias: Identifier; // emit name if @@ -446,7 +467,7 @@ namespace ts { } const statements: Statement[] = []; - if (!node.decorators) { + if (!isDecoratedClass) { // ${modifiers} class ${name} ${heritageClauses} { // ${members} // } @@ -491,7 +512,7 @@ namespace ts { if (isNamespaceExport(node)) { addExportMemberAssignment(statements, node); } - else if (node.decorators) { + else if (isDecoratedClass) { if (isDefaultExternalModuleExport(node)) { statements.push(createExportDefault(getLocalName(node))); } @@ -644,19 +665,11 @@ namespace ts { /*location*/ location); } - // When emitting as a *default* export, we'll add a subsequent `export default` statement, - // so we should only be creating a local binding without any modifiers. - // Otherwise, we need preserve and visit all the modifiers. - const bindingModifiers = - isDefaultExternalModuleExport(node) - ? undefined - : visitNodes(node.modifiers, visitor, isModifier); - // let ${name} = ${classExpression}; addNode(statements, setOriginalNode( createVariableStatement( - bindingModifiers, + /*modifiers*/ undefined, createLetDeclarationList([ createVariableDeclaration( getDeclarationName(node, /*allowComments*/ true), diff --git a/tests/baselines/reference/decoratorOnClass2.es6.js b/tests/baselines/reference/decoratorOnClass2.es6.js index 872f241bc9c..d1258af98b9 100644 --- a/tests/baselines/reference/decoratorOnClass2.es6.js +++ b/tests/baselines/reference/decoratorOnClass2.es6.js @@ -14,9 +14,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, 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; return c > 3 && r && Object.defineProperty(target, key, r), r; }; -export let C = class C { +let C = class C { }; C = __decorate([ dec ], C); +export { C }; let c = new C(); diff --git a/tests/baselines/reference/decoratorOnClass6.es6.js b/tests/baselines/reference/decoratorOnClass6.es6.js index 03b8ace2b5b..d8330a57ef6 100644 --- a/tests/baselines/reference/decoratorOnClass6.es6.js +++ b/tests/baselines/reference/decoratorOnClass6.es6.js @@ -17,11 +17,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, return c > 3 && r && Object.defineProperty(target, key, r), r; }; let C_1; -export let C = C_1 = class C { +let C = C_1 = class C { static x() { return C_1.y; } }; C.y = 1; C = C_1 = __decorate([ dec ], C); +export { C }; let c = new C(); diff --git a/tests/baselines/reference/decoratorOnClassConstructor2.js b/tests/baselines/reference/decoratorOnClassConstructor2.js index 59659c32f7a..5fc5501c329 100644 --- a/tests/baselines/reference/decoratorOnClassConstructor2.js +++ b/tests/baselines/reference/decoratorOnClassConstructor2.js @@ -49,7 +49,6 @@ var C = (function (_super) { } return C; }(_0_ts_1.base)); -exports.C = C; C = __decorate([ __param(0, _0_ts_2.foo) ], C);