diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index 7d8bc6f8eab22..c50afa47acf8b 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -1911,9 +1911,9 @@ export function transformClassFields(context: TransformationContext): (x: Source // HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using // a lexical declaration such as a LexicalDeclaration or a ClassDeclaration. - const staticProperties = getStaticPropertiesAndClassStaticBlock(node); - if (some(staticProperties)) { - addPropertyOrClassStaticBlockStatements(statements, staticProperties, factory.getInternalName(node)); + const staticDeclarations = getStaticPropertiesAndClassStaticBlock(node); + if (some(staticDeclarations)) { + addPropertyOrClassStaticBlockStatements(statements, staticDeclarations, factory.getInternalName(node)); } } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 75656cf5aefab..b0f1b30e7b236 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -80,6 +80,7 @@ import { isCatchClause, isClassElement, isClassLike, + isClassStaticBlockDeclaration, isComputedPropertyName, isDecorator, isElementAccessExpression, @@ -221,10 +222,11 @@ const enum ClassFacts { HasStaticInitializedProperties = 1 << 0, HasClassOrConstructorParameterDecorators = 1 << 1, HasMemberDecorators = 1 << 2, - IsExportOfNamespace = 1 << 3, - IsNamedExternalExport = 1 << 4, - IsDefaultExternalExport = 1 << 5, - IsDerivedClass = 1 << 6, + HasStaticBlocks = 1 << 3, + IsExportOfNamespace = 1 << 4, + IsNamedExternalExport = 1 << 5, + IsDefaultExternalExport = 1 << 6, + IsDerivedClass = 1 << 7, HasAnyDecorators = HasClassOrConstructorParameterDecorators | HasMemberDecorators, MayNeedImmediatelyInvokedFunctionExpression = HasAnyDecorators | HasStaticInitializedProperties, @@ -856,6 +858,7 @@ export function transformTypeScript(context: TransformationContext): Transformer function getClassFacts(node: ClassDeclaration) { let facts = ClassFacts.None; if (some(getProperties(node, /*requireInitializer*/ true, /*isStatic*/ true))) facts |= ClassFacts.HasStaticInitializedProperties; + if (node.transformFlags & TransformFlags.ContainsClassFields && some(node.members, isClassStaticBlockDeclaration)) facts |= ClassFacts.HasStaticBlocks; const extendsClauseElement = getEffectiveBaseTypeNode(node); if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass; if (classOrConstructorParameterIsDecorated(legacyDecorators, node)) facts |= ClassFacts.HasClassOrConstructorParameterDecorators; @@ -885,7 +888,8 @@ export function transformTypeScript(context: TransformationContext): Transformer if ( !isClassLikeDeclarationWithTypeScriptSyntax(node) && !classOrConstructorParameterIsDecorated(legacyDecorators, node) && - !isExportOfNamespace(node) + !isExportOfNamespace(node) && + !(facts & ClassFacts.HasStaticBlocks && languageVersion < ScriptTarget.ES2022) ) { return factory.updateClassDeclaration( node, @@ -916,8 +920,7 @@ export function transformTypeScript(context: TransformationContext): Transformer } const needsName = moveModifiers && !node.name || - facts & ClassFacts.HasMemberDecorators || - facts & ClassFacts.HasStaticInitializedProperties; + facts & (ClassFacts.HasMemberDecorators | ClassFacts.HasStaticInitializedProperties | ClassFacts.HasStaticBlocks); const name = needsName ? node.name ?? factory.getGeneratedNameForNode(node) : diff --git a/tests/baselines/reference/classStaticBlock29(target=es2015).js b/tests/baselines/reference/classStaticBlock29(target=es2015).js new file mode 100644 index 0000000000000..98cb5a545dd0e --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es2015).js @@ -0,0 +1,41 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +//// [classStaticBlock29.ts] +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; + static { + this.demo = 1; + } +} + +export function makeCls() { + return class { + static demo: number; + static { + this.demo = 1; + } + }; +} + + +//// [classStaticBlock29.js] +// https://github.com/microsoft/TypeScript/issues/60879 +var _a; +class default_1 { +} +_a = default_1; +(() => { + _a.demo = 1; +})(); +export default default_1; +export function makeCls() { + var _b; + return _b = class { + }, + (() => { + _b.demo = 1; + })(), + _b; +} diff --git a/tests/baselines/reference/classStaticBlock29(target=es2015).symbols b/tests/baselines/reference/classStaticBlock29(target=es2015).symbols new file mode 100644 index 0000000000000..3e1cabd8d2374 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es2015).symbols @@ -0,0 +1,33 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + + static { + this.demo = 1; +>this.demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) +>this : Symbol(default, Decl(classStaticBlock29.ts, 0, 0)) +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + } +} + +export function makeCls() { +>makeCls : Symbol(makeCls, Decl(classStaticBlock29.ts, 7, 1)) + + return class { + static demo: number; +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + + static { + this.demo = 1; +>this.demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) +>this : Symbol((Anonymous class), Decl(classStaticBlock29.ts, 10, 8)) +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + } + }; +} + diff --git a/tests/baselines/reference/classStaticBlock29(target=es2015).types b/tests/baselines/reference/classStaticBlock29(target=es2015).types new file mode 100644 index 0000000000000..179733b2118c1 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es2015).types @@ -0,0 +1,53 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof default +> : ^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } +} + +export function makeCls() { +>makeCls : () => typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return class { +>class { static demo: number; static { this.demo = 1; } } : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } + }; +} + diff --git a/tests/baselines/reference/classStaticBlock29(target=es2022).js b/tests/baselines/reference/classStaticBlock29(target=es2022).js new file mode 100644 index 0000000000000..25ea3922e2f89 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es2022).js @@ -0,0 +1,38 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +//// [classStaticBlock29.ts] +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; + static { + this.demo = 1; + } +} + +export function makeCls() { + return class { + static demo: number; + static { + this.demo = 1; + } + }; +} + + +//// [classStaticBlock29.js] +// https://github.com/microsoft/TypeScript/issues/60879 +export default class { + static demo; + static { + this.demo = 1; + } +} +export function makeCls() { + return class { + static demo; + static { + this.demo = 1; + } + }; +} diff --git a/tests/baselines/reference/classStaticBlock29(target=es2022).symbols b/tests/baselines/reference/classStaticBlock29(target=es2022).symbols new file mode 100644 index 0000000000000..3e1cabd8d2374 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es2022).symbols @@ -0,0 +1,33 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + + static { + this.demo = 1; +>this.demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) +>this : Symbol(default, Decl(classStaticBlock29.ts, 0, 0)) +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + } +} + +export function makeCls() { +>makeCls : Symbol(makeCls, Decl(classStaticBlock29.ts, 7, 1)) + + return class { + static demo: number; +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + + static { + this.demo = 1; +>this.demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) +>this : Symbol((Anonymous class), Decl(classStaticBlock29.ts, 10, 8)) +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + } + }; +} + diff --git a/tests/baselines/reference/classStaticBlock29(target=es2022).types b/tests/baselines/reference/classStaticBlock29(target=es2022).types new file mode 100644 index 0000000000000..179733b2118c1 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es2022).types @@ -0,0 +1,53 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof default +> : ^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } +} + +export function makeCls() { +>makeCls : () => typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return class { +>class { static demo: number; static { this.demo = 1; } } : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } + }; +} + diff --git a/tests/baselines/reference/classStaticBlock29(target=es5).js b/tests/baselines/reference/classStaticBlock29(target=es5).js new file mode 100644 index 0000000000000..93c6a558793ac --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es5).js @@ -0,0 +1,50 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +//// [classStaticBlock29.ts] +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; + static { + this.demo = 1; + } +} + +export function makeCls() { + return class { + static demo: number; + static { + this.demo = 1; + } + }; +} + + +//// [classStaticBlock29.js] +"use strict"; +// https://github.com/microsoft/TypeScript/issues/60879 +var _a; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.makeCls = makeCls; +var default_1 = /** @class */ (function () { + function default_1() { + } + return default_1; +}()); +_a = default_1; +(function () { + _a.demo = 1; +})(); +exports.default = default_1; +function makeCls() { + var _b; + return _b = /** @class */ (function () { + function class_1() { + } + return class_1; + }()), + (function () { + _b.demo = 1; + })(), + _b; +} diff --git a/tests/baselines/reference/classStaticBlock29(target=es5).symbols b/tests/baselines/reference/classStaticBlock29(target=es5).symbols new file mode 100644 index 0000000000000..3e1cabd8d2374 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es5).symbols @@ -0,0 +1,33 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + + static { + this.demo = 1; +>this.demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) +>this : Symbol(default, Decl(classStaticBlock29.ts, 0, 0)) +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + } +} + +export function makeCls() { +>makeCls : Symbol(makeCls, Decl(classStaticBlock29.ts, 7, 1)) + + return class { + static demo: number; +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + + static { + this.demo = 1; +>this.demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) +>this : Symbol((Anonymous class), Decl(classStaticBlock29.ts, 10, 8)) +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + } + }; +} + diff --git a/tests/baselines/reference/classStaticBlock29(target=es5).types b/tests/baselines/reference/classStaticBlock29(target=es5).types new file mode 100644 index 0000000000000..179733b2118c1 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=es5).types @@ -0,0 +1,53 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof default +> : ^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } +} + +export function makeCls() { +>makeCls : () => typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return class { +>class { static demo: number; static { this.demo = 1; } } : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } + }; +} + diff --git a/tests/baselines/reference/classStaticBlock29(target=esnext).js b/tests/baselines/reference/classStaticBlock29(target=esnext).js new file mode 100644 index 0000000000000..25ea3922e2f89 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=esnext).js @@ -0,0 +1,38 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +//// [classStaticBlock29.ts] +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; + static { + this.demo = 1; + } +} + +export function makeCls() { + return class { + static demo: number; + static { + this.demo = 1; + } + }; +} + + +//// [classStaticBlock29.js] +// https://github.com/microsoft/TypeScript/issues/60879 +export default class { + static demo; + static { + this.demo = 1; + } +} +export function makeCls() { + return class { + static demo; + static { + this.demo = 1; + } + }; +} diff --git a/tests/baselines/reference/classStaticBlock29(target=esnext).symbols b/tests/baselines/reference/classStaticBlock29(target=esnext).symbols new file mode 100644 index 0000000000000..3e1cabd8d2374 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=esnext).symbols @@ -0,0 +1,33 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + + static { + this.demo = 1; +>this.demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) +>this : Symbol(default, Decl(classStaticBlock29.ts, 0, 0)) +>demo : Symbol(default.demo, Decl(classStaticBlock29.ts, 2, 22)) + } +} + +export function makeCls() { +>makeCls : Symbol(makeCls, Decl(classStaticBlock29.ts, 7, 1)) + + return class { + static demo: number; +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + + static { + this.demo = 1; +>this.demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) +>this : Symbol((Anonymous class), Decl(classStaticBlock29.ts, 10, 8)) +>demo : Symbol((Anonymous class).demo, Decl(classStaticBlock29.ts, 10, 16)) + } + }; +} + diff --git a/tests/baselines/reference/classStaticBlock29(target=esnext).types b/tests/baselines/reference/classStaticBlock29(target=esnext).types new file mode 100644 index 0000000000000..179733b2118c1 --- /dev/null +++ b/tests/baselines/reference/classStaticBlock29(target=esnext).types @@ -0,0 +1,53 @@ +//// [tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts] //// + +=== classStaticBlock29.ts === +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof default +> : ^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } +} + +export function makeCls() { +>makeCls : () => typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return class { +>class { static demo: number; static { this.demo = 1; } } : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + static demo: number; +>demo : number +> : ^^^^^^ + + static { + this.demo = 1; +>this.demo = 1 : 1 +> : ^ +>this.demo : number +> : ^^^^^^ +>this : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>demo : number +> : ^^^^^^ +>1 : 1 +> : ^ + } + }; +} + diff --git a/tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts b/tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts new file mode 100644 index 0000000000000..28b786f747a80 --- /dev/null +++ b/tests/cases/conformance/classes/classStaticBlock/classStaticBlock29.ts @@ -0,0 +1,20 @@ +// @strict: true +// @target: esnext, es2022, es2015, es5 + +// https://github.com/microsoft/TypeScript/issues/60879 + +export default class { + static demo: number; + static { + this.demo = 1; + } +} + +export function makeCls() { + return class { + static demo: number; + static { + this.demo = 1; + } + }; +}