diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7d6c6a725ab60..b01c145c24b15 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3154,7 +3154,7 @@ namespace ts { } function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) { - const globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike; + const globalFlagsToPass = globalFlags & (TypeFormatFlags.WriteOwnNameForAnyLike | TypeFormatFlags.WriteClassExpressionAsTypeLiteral); let inObjectTypeLiteral = false; return writeType(type, globalFlags); @@ -3266,6 +3266,11 @@ namespace ts { writeTypeList(type.typeArguments.slice(0, getTypeReferenceArity(type)), SyntaxKind.CommaToken); writePunctuation(writer, SyntaxKind.CloseBracketToken); } + else if (flags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral && + type.symbol.valueDeclaration && + type.symbol.valueDeclaration.kind === SyntaxKind.ClassExpression) { + writeAnonymousType(getDeclaredTypeOfClassOrInterface(type.symbol), flags); + } else { // Write the type reference in the format f.g.C where A and B are type arguments // for outer type parameters, and f and g are the respective declaring containers of those @@ -3313,7 +3318,9 @@ namespace ts { const symbol = type.symbol; if (symbol) { // Always use 'typeof T' for type of class, enum, and module objects - if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) || + if (symbol.flags & SymbolFlags.Class && + !getBaseTypeVariableOfClass(symbol) && + !(symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && flags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral) || symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule)) { writeTypeOfSymbol(type, flags); } @@ -3335,12 +3342,23 @@ namespace ts { else { // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead // of types allows us to catch circular references to instantiations of the same anonymous type + // However, in case of class expressions, we want to write both the static side and the instance side. + // We skip adding the static side so that the instance side has a chance to be written + // before checking for circular references. if (!symbolStack) { symbolStack = []; } - symbolStack.push(symbol); - writeLiteralType(type, flags); - symbolStack.pop(); + const isConstructorObject = type.flags & TypeFlags.Object && + getObjectFlags(type) & ObjectFlags.Anonymous && + type.symbol && type.symbol.flags & SymbolFlags.Class; + if (isConstructorObject) { + writeLiteralType(type, flags); + } + else { + symbolStack.push(symbol); + writeLiteralType(type, flags); + symbolStack.pop(); + } } } else { @@ -3459,6 +3477,14 @@ namespace ts { buildIndexSignatureDisplay(resolved.stringIndexInfo, writer, IndexKind.String, enclosingDeclaration, globalFlags, symbolStack); buildIndexSignatureDisplay(resolved.numberIndexInfo, writer, IndexKind.Number, enclosingDeclaration, globalFlags, symbolStack); for (const p of resolved.properties) { + if (globalFlags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral) { + if (p.flags & SymbolFlags.Prototype) { + continue; + } + if (getDeclarationModifierFlagsFromSymbol(p) & (ModifierFlags.Private | ModifierFlags.Protected)) { + writer.reportPrivateInBaseOfClassExpression(p.name); + } + } const t = getTypeOfSymbol(p); if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) { const signatures = getSignaturesOfType(t, SignatureKind.Call); @@ -3473,7 +3499,7 @@ namespace ts { writePropertyWithModifiers(p); writePunctuation(writer, SyntaxKind.ColonToken); writeSpace(writer); - writeType(t, TypeFormatFlags.None); + writeType(t, globalFlags & TypeFormatFlags.WriteClassExpressionAsTypeLiteral); writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 4d06b41f377aa..3cc85aaa24be4 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -190,7 +190,7 @@ namespace ts { const writer = createTextWriter(newLine); writer.trackSymbol = trackSymbol; writer.reportInaccessibleThisError = reportInaccessibleThisError; - writer.reportIllegalExtends = reportIllegalExtends; + writer.reportPrivateInBaseOfClassExpression = reportPrivateInBaseOfClassExpression; writer.writeKeyword = writer.write; writer.writeOperator = writer.write; writer.writePunctuation = writer.write; @@ -314,11 +314,11 @@ namespace ts { recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning)); } - function reportIllegalExtends() { + function reportPrivateInBaseOfClassExpression(propertyName: string) { if (errorNameNode) { reportedDeclarationError = true; - emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.extends_clause_of_exported_class_0_refers_to_a_type_whose_name_cannot_be_referenced, - declarationNameToString(errorNameNode))); + emitterDiagnostics.add( + createDiagnosticForNode(errorNameNode, Diagnostics.Property_0_of_exported_class_expression_may_not_be_private_or_protected, propertyName)); } } @@ -344,7 +344,9 @@ namespace ts { } else { errorNameNode = declaration.name; - const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | + const format = TypeFormatFlags.UseTypeOfFunction | + TypeFormatFlags.WriteClassExpressionAsTypeLiteral | + TypeFormatFlags.UseTypeAliasValue | (shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0); resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer); errorNameNode = undefined; @@ -360,7 +362,11 @@ namespace ts { } else { errorNameNode = signature.name; - resolver.writeReturnTypeOfSignatureDeclaration(signature, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer); + resolver.writeReturnTypeOfSignatureDeclaration( + signature, + enclosingDeclaration, + TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral, + writer); errorNameNode = undefined; } } @@ -621,7 +627,11 @@ namespace ts { write(tempVarName); write(": "); writer.getSymbolAccessibilityDiagnostic = () => diagnostic; - resolver.writeTypeOfExpression(expr, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer); + resolver.writeTypeOfExpression( + expr, + enclosingDeclaration, + TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral, + writer); write(";"); writeLine(); return tempVarName; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4aee7a37a8878..c5b74943dcda5 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2432,9 +2432,9 @@ "category": "Error", "code": 4092 }, - "'extends' clause of exported class '{0}' refers to a type whose name cannot be referenced.": { + "Property '{0}' of exported class expression may not be private or protected.": { "category": "Error", - "code": 4093 + "code": 4094 }, "The current host does not support the '{0}' option.": { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0283c45f2e16c..0cade7f2cbca6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2648,24 +2648,25 @@ namespace ts { // with import statements it previously saw (but chose not to emit). trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; reportInaccessibleThisError(): void; - reportIllegalExtends(): void; + reportPrivateInBaseOfClassExpression(propertyName: string): void; } export const enum TypeFormatFlags { - None = 0x00000000, - WriteArrayAsGenericType = 0x00000001, // Write Array instead T[] - UseTypeOfFunction = 0x00000002, // Write typeof instead of function type literal - NoTruncation = 0x00000004, // Don't truncate typeToString result - WriteArrowStyleSignature = 0x00000008, // Write arrow style signature - WriteOwnNameForAnyLike = 0x00000010, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc) - WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature - InElementType = 0x00000040, // Writing an array or union element type - UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type) - InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type - InTypeAlias = 0x00000200, // Writing type in type alias declaration - UseTypeAliasValue = 0x00000400, // Serialize the type instead of using type-alias. This is needed when we emit declaration file. - SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type. - AddUndefined = 0x00001000, // Add undefined to types of initialized, non-optional parameters + None = 0, + WriteArrayAsGenericType = 1 << 0, // Write Array instead T[] + UseTypeOfFunction = 1 << 2, // Write typeof instead of function type literal + NoTruncation = 1 << 3, // Don't truncate typeToString result + WriteArrowStyleSignature = 1 << 4, // Write arrow style signature + WriteOwnNameForAnyLike = 1 << 5, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc) + WriteTypeArgumentsOfSignature = 1 << 6, // Write the type arguments instead of type parameters of the signature + InElementType = 1 << 7, // Writing an array or union element type + UseFullyQualifiedType = 1 << 8, // Write out the fully qualified type name (eg. Module.Type, instead of Type) + InFirstTypeArgument = 1 << 9, // Writing first type argument of the instantiated type + InTypeAlias = 1 << 10, // Writing type in type alias declaration + UseTypeAliasValue = 1 << 11, // Serialize the type instead of using type-alias. This is needed when we emit declaration file. + SuppressAnyReturnType = 1 << 12, // If the return type is any-like, don't offer a return type. + AddUndefined = 1 << 13, // Add undefined to types of initialized, non-optional parameters + WriteClassExpressionAsTypeLiteral = 1 << 14, // Write a type literal instead of (Anonymous class) } export const enum SymbolFormatFlags { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index befb1c4ba774d..3c3710c1cc558 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -68,7 +68,7 @@ namespace ts { clear: () => str = "", trackSymbol: noop, reportInaccessibleThisError: noop, - reportIllegalExtends: noop + reportPrivateInBaseOfClassExpression: noop, }; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index c8b710789ad43..0965eb4dad790 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1128,7 +1128,7 @@ namespace ts { clear: resetWriter, trackSymbol: noop, reportInaccessibleThisError: noop, - reportIllegalExtends: noop + reportPrivateInBaseOfClassExpression: noop, }; function writeIndent() { diff --git a/tests/baselines/reference/declarationEmitExpressionInExtends4.errors.txt b/tests/baselines/reference/declarationEmitExpressionInExtends4.errors.txt index 549052128365b..569e5aa355fce 100644 --- a/tests/baselines/reference/declarationEmitExpressionInExtends4.errors.txt +++ b/tests/baselines/reference/declarationEmitExpressionInExtends4.errors.txt @@ -1,23 +1,17 @@ -tests/cases/compiler/declarationEmitExpressionInExtends4.ts(1,10): error TS4060: Return type of exported function has or is using private name 'D'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(5,17): error TS2315: Type 'D' is not generic. -tests/cases/compiler/declarationEmitExpressionInExtends4.ts(5,17): error TS4020: 'extends' clause of exported class 'C' has or is using private name 'D'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(9,18): error TS2304: Cannot find name 'SomeUndefinedFunction'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(14,18): error TS2304: Cannot find name 'SomeUndefinedFunction'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(14,18): error TS4020: 'extends' clause of exported class 'C3' has or is using private name 'SomeUndefinedFunction'. -==== tests/cases/compiler/declarationEmitExpressionInExtends4.ts (6 errors) ==== +==== tests/cases/compiler/declarationEmitExpressionInExtends4.ts (4 errors) ==== function getSomething() { - ~~~~~~~~~~~~ -!!! error TS4060: Return type of exported function has or is using private name 'D'. return class D { } } class C extends getSomething() { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2315: Type 'D' is not generic. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS4020: 'extends' clause of exported class 'C' has or is using private name 'D'. } diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile.js b/tests/baselines/reference/emitClassExpressionInDeclarationFile.js new file mode 100644 index 0000000000000..ab64fe003be76 --- /dev/null +++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile.js @@ -0,0 +1,132 @@ +//// [emitClassExpressionInDeclarationFile.ts] +export var simpleExample = class { + static getTags() { } + tags() { } +} +export var circularReference = class C { + static getTags(c: C): C { return c } + tags(c: C): C { return c } +} + +// repro from #15066 +export class FooItem { + foo(): void { } + name?: string; +} + +export type Constructor = new(...args: any[]) => T; +export function WithTags>(Base: T) { + return class extends Base { + static getTags(): void { } + tags(): void { } + } +} + +export class Test extends WithTags(FooItem) {} + +const test = new Test(); + +Test.getTags() +test.tags(); + + +//// [emitClassExpressionInDeclarationFile.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +exports.simpleExample = (function () { + function class_1() { + } + class_1.getTags = function () { }; + class_1.prototype.tags = function () { }; + return class_1; +}()); +exports.circularReference = (function () { + function C() { + } + C.getTags = function (c) { return c; }; + C.prototype.tags = function (c) { return c; }; + return C; +}()); +// repro from #15066 +var FooItem = (function () { + function FooItem() { + } + FooItem.prototype.foo = function () { }; + return FooItem; +}()); +exports.FooItem = FooItem; +function WithTags(Base) { + return (function (_super) { + __extends(class_2, _super); + function class_2() { + return _super !== null && _super.apply(this, arguments) || this; + } + class_2.getTags = function () { }; + class_2.prototype.tags = function () { }; + return class_2; + }(Base)); +} +exports.WithTags = WithTags; +var Test = (function (_super) { + __extends(Test, _super); + function Test() { + return _super !== null && _super.apply(this, arguments) || this; + } + return Test; +}(WithTags(FooItem))); +exports.Test = Test; +var test = new Test(); +Test.getTags(); +test.tags(); + + +//// [emitClassExpressionInDeclarationFile.d.ts] +export declare var simpleExample: { + new (): { + tags(): void; + }; + getTags(): void; +}; +export declare var circularReference: { + new (): { + tags(c: any): any; + }; + getTags(c: { + tags(c: any): any; + }): { + tags(c: any): any; + }; +}; +export declare class FooItem { + foo(): void; + name?: string; +} +export declare type Constructor = new (...args: any[]) => T; +export declare function WithTags>(Base: T): { + new (...args: any[]): { + tags(): void; + foo(): void; + name?: string; + }; + getTags(): void; +} & T; +declare const Test_base: { + new (...args: any[]): { + tags(): void; + foo(): void; + name?: string; + }; + getTags(): void; +} & typeof FooItem; +export declare class Test extends Test_base { +} diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile.symbols b/tests/baselines/reference/emitClassExpressionInDeclarationFile.symbols new file mode 100644 index 0000000000000..537838937c5ab --- /dev/null +++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile.symbols @@ -0,0 +1,84 @@ +=== tests/cases/compiler/emitClassExpressionInDeclarationFile.ts === +export var simpleExample = class { +>simpleExample : Symbol(simpleExample, Decl(emitClassExpressionInDeclarationFile.ts, 0, 10)) + + static getTags() { } +>getTags : Symbol(simpleExample.getTags, Decl(emitClassExpressionInDeclarationFile.ts, 0, 34)) + + tags() { } +>tags : Symbol(simpleExample.tags, Decl(emitClassExpressionInDeclarationFile.ts, 1, 24)) +} +export var circularReference = class C { +>circularReference : Symbol(circularReference, Decl(emitClassExpressionInDeclarationFile.ts, 4, 10)) +>C : Symbol(C, Decl(emitClassExpressionInDeclarationFile.ts, 4, 30)) + + static getTags(c: C): C { return c } +>getTags : Symbol(C.getTags, Decl(emitClassExpressionInDeclarationFile.ts, 4, 40)) +>c : Symbol(c, Decl(emitClassExpressionInDeclarationFile.ts, 5, 19)) +>C : Symbol(C, Decl(emitClassExpressionInDeclarationFile.ts, 4, 30)) +>C : Symbol(C, Decl(emitClassExpressionInDeclarationFile.ts, 4, 30)) +>c : Symbol(c, Decl(emitClassExpressionInDeclarationFile.ts, 5, 19)) + + tags(c: C): C { return c } +>tags : Symbol(C.tags, Decl(emitClassExpressionInDeclarationFile.ts, 5, 40)) +>c : Symbol(c, Decl(emitClassExpressionInDeclarationFile.ts, 6, 9)) +>C : Symbol(C, Decl(emitClassExpressionInDeclarationFile.ts, 4, 30)) +>C : Symbol(C, Decl(emitClassExpressionInDeclarationFile.ts, 4, 30)) +>c : Symbol(c, Decl(emitClassExpressionInDeclarationFile.ts, 6, 9)) +} + +// repro from #15066 +export class FooItem { +>FooItem : Symbol(FooItem, Decl(emitClassExpressionInDeclarationFile.ts, 7, 1)) + + foo(): void { } +>foo : Symbol(FooItem.foo, Decl(emitClassExpressionInDeclarationFile.ts, 10, 22)) + + name?: string; +>name : Symbol(FooItem.name, Decl(emitClassExpressionInDeclarationFile.ts, 11, 19)) +} + +export type Constructor = new(...args: any[]) => T; +>Constructor : Symbol(Constructor, Decl(emitClassExpressionInDeclarationFile.ts, 13, 1)) +>T : Symbol(T, Decl(emitClassExpressionInDeclarationFile.ts, 15, 24)) +>args : Symbol(args, Decl(emitClassExpressionInDeclarationFile.ts, 15, 33)) +>T : Symbol(T, Decl(emitClassExpressionInDeclarationFile.ts, 15, 24)) + +export function WithTags>(Base: T) { +>WithTags : Symbol(WithTags, Decl(emitClassExpressionInDeclarationFile.ts, 15, 54)) +>T : Symbol(T, Decl(emitClassExpressionInDeclarationFile.ts, 16, 25)) +>Constructor : Symbol(Constructor, Decl(emitClassExpressionInDeclarationFile.ts, 13, 1)) +>FooItem : Symbol(FooItem, Decl(emitClassExpressionInDeclarationFile.ts, 7, 1)) +>Base : Symbol(Base, Decl(emitClassExpressionInDeclarationFile.ts, 16, 57)) +>T : Symbol(T, Decl(emitClassExpressionInDeclarationFile.ts, 16, 25)) + + return class extends Base { +>Base : Symbol(Base, Decl(emitClassExpressionInDeclarationFile.ts, 16, 57)) + + static getTags(): void { } +>getTags : Symbol((Anonymous class).getTags, Decl(emitClassExpressionInDeclarationFile.ts, 17, 31)) + + tags(): void { } +>tags : Symbol((Anonymous class).tags, Decl(emitClassExpressionInDeclarationFile.ts, 18, 34)) + } +} + +export class Test extends WithTags(FooItem) {} +>Test : Symbol(Test, Decl(emitClassExpressionInDeclarationFile.ts, 21, 1)) +>WithTags : Symbol(WithTags, Decl(emitClassExpressionInDeclarationFile.ts, 15, 54)) +>FooItem : Symbol(FooItem, Decl(emitClassExpressionInDeclarationFile.ts, 7, 1)) + +const test = new Test(); +>test : Symbol(test, Decl(emitClassExpressionInDeclarationFile.ts, 25, 5)) +>Test : Symbol(Test, Decl(emitClassExpressionInDeclarationFile.ts, 21, 1)) + +Test.getTags() +>Test.getTags : Symbol((Anonymous class).getTags, Decl(emitClassExpressionInDeclarationFile.ts, 17, 31)) +>Test : Symbol(Test, Decl(emitClassExpressionInDeclarationFile.ts, 21, 1)) +>getTags : Symbol((Anonymous class).getTags, Decl(emitClassExpressionInDeclarationFile.ts, 17, 31)) + +test.tags(); +>test.tags : Symbol((Anonymous class).tags, Decl(emitClassExpressionInDeclarationFile.ts, 18, 34)) +>test : Symbol(test, Decl(emitClassExpressionInDeclarationFile.ts, 25, 5)) +>tags : Symbol((Anonymous class).tags, Decl(emitClassExpressionInDeclarationFile.ts, 18, 34)) + diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile.types b/tests/baselines/reference/emitClassExpressionInDeclarationFile.types new file mode 100644 index 0000000000000..3d5190262de2e --- /dev/null +++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile.types @@ -0,0 +1,91 @@ +=== tests/cases/compiler/emitClassExpressionInDeclarationFile.ts === +export var simpleExample = class { +>simpleExample : typeof simpleExample +>class { static getTags() { } tags() { }} : typeof simpleExample + + static getTags() { } +>getTags : () => void + + tags() { } +>tags : () => void +} +export var circularReference = class C { +>circularReference : typeof C +>class C { static getTags(c: C): C { return c } tags(c: C): C { return c }} : typeof C +>C : typeof C + + static getTags(c: C): C { return c } +>getTags : (c: C) => C +>c : C +>C : C +>C : C +>c : C + + tags(c: C): C { return c } +>tags : (c: C) => C +>c : C +>C : C +>C : C +>c : C +} + +// repro from #15066 +export class FooItem { +>FooItem : FooItem + + foo(): void { } +>foo : () => void + + name?: string; +>name : string +} + +export type Constructor = new(...args: any[]) => T; +>Constructor : Constructor +>T : T +>args : any[] +>T : T + +export function WithTags>(Base: T) { +>WithTags : >(Base: T) => { new (...args: any[]): (Anonymous class); prototype: WithTags.(Anonymous class); getTags(): void; } & T +>T : T +>Constructor : Constructor +>FooItem : FooItem +>Base : T +>T : T + + return class extends Base { +>class extends Base { static getTags(): void { } tags(): void { } } : { new (...args: any[]): (Anonymous class); prototype: WithTags.(Anonymous class); getTags(): void; } & T +>Base : FooItem + + static getTags(): void { } +>getTags : () => void + + tags(): void { } +>tags : () => void + } +} + +export class Test extends WithTags(FooItem) {} +>Test : Test +>WithTags(FooItem) : WithTags.(Anonymous class) & FooItem +>WithTags : >(Base: T) => { new (...args: any[]): (Anonymous class); prototype: WithTags.(Anonymous class); getTags(): void; } & T +>FooItem : typeof FooItem + +const test = new Test(); +>test : Test +>new Test() : Test +>Test : typeof Test + +Test.getTags() +>Test.getTags() : void +>Test.getTags : () => void +>Test : typeof Test +>getTags : () => void + +test.tags(); +>test.tags() : void +>test.tags : () => void +>test : Test +>tags : () => void + diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.errors.txt b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.errors.txt new file mode 100644 index 0000000000000..4541cf2a58aea --- /dev/null +++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.errors.txt @@ -0,0 +1,41 @@ +tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts(1,12): error TS4094: Property 'p' of exported class expression may not be private or protected. +tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts(1,12): error TS4094: Property 'ps' of exported class expression may not be private or protected. +tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts(16,17): error TS4094: Property 'property' of exported class expression may not be private or protected. + + +==== tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts (3 errors) ==== + export var noPrivates = class { + ~~~~~~~~~~ +!!! error TS4094: Property 'p' of exported class expression may not be private or protected. + ~~~~~~~~~~ +!!! error TS4094: Property 'ps' of exported class expression may not be private or protected. + static getTags() { } + tags() { } + private static ps = -1 + private p = 12 + } + + // altered repro from #15066 to add private property + export class FooItem { + foo(): void { } + name?: string; + private property = "capitalism" + } + + export type Constructor = new(...args: any[]) => T; + export function WithTags>(Base: T) { + ~~~~~~~~ +!!! error TS4094: Property 'property' of exported class expression may not be private or protected. + return class extends Base { + static getTags(): void { } + tags(): void { } + } + } + + export class Test extends WithTags(FooItem) {} + + const test = new Test(); + + Test.getTags() + test.tags(); + \ No newline at end of file diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.js b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.js new file mode 100644 index 0000000000000..e3a0aa4cb9949 --- /dev/null +++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.js @@ -0,0 +1,87 @@ +//// [emitClassExpressionInDeclarationFile2.ts] +export var noPrivates = class { + static getTags() { } + tags() { } + private static ps = -1 + private p = 12 +} + +// altered repro from #15066 to add private property +export class FooItem { + foo(): void { } + name?: string; + private property = "capitalism" +} + +export type Constructor = new(...args: any[]) => T; +export function WithTags>(Base: T) { + return class extends Base { + static getTags(): void { } + tags(): void { } + } +} + +export class Test extends WithTags(FooItem) {} + +const test = new Test(); + +Test.getTags() +test.tags(); + + +//// [emitClassExpressionInDeclarationFile2.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +exports.noPrivates = (_a = (function () { + function class_1() { + this.p = 12; + } + class_1.getTags = function () { }; + class_1.prototype.tags = function () { }; + return class_1; + }()), + _a.ps = -1, + _a); +// altered repro from #15066 to add private property +var FooItem = (function () { + function FooItem() { + this.property = "capitalism"; + } + FooItem.prototype.foo = function () { }; + return FooItem; +}()); +exports.FooItem = FooItem; +function WithTags(Base) { + return (function (_super) { + __extends(class_2, _super); + function class_2() { + return _super !== null && _super.apply(this, arguments) || this; + } + class_2.getTags = function () { }; + class_2.prototype.tags = function () { }; + return class_2; + }(Base)); +} +exports.WithTags = WithTags; +var Test = (function (_super) { + __extends(Test, _super); + function Test() { + return _super !== null && _super.apply(this, arguments) || this; + } + return Test; +}(WithTags(FooItem))); +exports.Test = Test; +var test = new Test(); +Test.getTags(); +test.tags(); +var _a; diff --git a/tests/cases/compiler/emitClassExpressionInDeclarationFile.ts b/tests/cases/compiler/emitClassExpressionInDeclarationFile.ts new file mode 100644 index 0000000000000..f99bcbd7efdaa --- /dev/null +++ b/tests/cases/compiler/emitClassExpressionInDeclarationFile.ts @@ -0,0 +1,30 @@ +// @declaration: true +export var simpleExample = class { + static getTags() { } + tags() { } +} +export var circularReference = class C { + static getTags(c: C): C { return c } + tags(c: C): C { return c } +} + +// repro from #15066 +export class FooItem { + foo(): void { } + name?: string; +} + +export type Constructor = new(...args: any[]) => T; +export function WithTags>(Base: T) { + return class extends Base { + static getTags(): void { } + tags(): void { } + } +} + +export class Test extends WithTags(FooItem) {} + +const test = new Test(); + +Test.getTags() +test.tags(); diff --git a/tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts b/tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts new file mode 100644 index 0000000000000..3175f2afce7df --- /dev/null +++ b/tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts @@ -0,0 +1,29 @@ +// @declaration: true +export var noPrivates = class { + static getTags() { } + tags() { } + private static ps = -1 + private p = 12 +} + +// altered repro from #15066 to add private property +export class FooItem { + foo(): void { } + name?: string; + private property = "capitalism" +} + +export type Constructor = new(...args: any[]) => T; +export function WithTags>(Base: T) { + return class extends Base { + static getTags(): void { } + tags(): void { } + } +} + +export class Test extends WithTags(FooItem) {} + +const test = new Test(); + +Test.getTags() +test.tags();