mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Component commits:5810765259Emit defineProperty calls before param prop assignments Note that I restricted this to --useDefineForClassFields is true. Nothing changes when it's off. I think this is the correct fix for a patch release. However, in principal there's nothing wrong with moving parameter property initialisation after property declaration initialisation. It would be Extremely Bad and Wrong to rely on this working: ```ts class C { p = this.q // what is q? constructor(public q: number) { } } ``` But today it does, and probably somebody relies on it without knowing.ec7959091aPut parameter property initialiser into defineProperty's valuebe863550b7Merge branch 'master' into fix-defineProperty-parameter-property-emit8ff59b98b8Combine ES5/ESNext into one test
This commit is contained in:
committed by
Nathan Shively-Sanders
parent
d5bcb6f904
commit
c021b28597
@@ -10,9 +10,9 @@ namespace ts {
|
||||
/**
|
||||
* Transforms ECMAScript Class Syntax.
|
||||
* TypeScript parameter property syntax is transformed in the TypeScript transformer.
|
||||
* For now, this transforms public field declarations using TypeScript class semantics
|
||||
* (where the declarations get elided and initializers are transformed as assignments in the constructor).
|
||||
* Eventually, this transform will change to the ECMAScript semantics (with Object.defineProperty).
|
||||
* For now, this transforms public field declarations using TypeScript class semantics,
|
||||
* where declarations are elided and initializers are transformed as assignments in the constructor.
|
||||
* When --useDefineForClassFields is on, this transforms to ECMAScript semantics, with Object.defineProperty.
|
||||
*/
|
||||
export function transformClassFields(context: TransformationContext) {
|
||||
const {
|
||||
@@ -294,7 +294,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transformConstructorBody(node: ClassDeclaration | ClassExpression, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) {
|
||||
const properties = getProperties(node, /*requireInitializer*/ !context.getCompilerOptions().useDefineForClassFields, /*isStatic*/ false);
|
||||
const useDefineForClassFields = context.getCompilerOptions().useDefineForClassFields;
|
||||
const properties = getProperties(node, /*requireInitializer*/ !useDefineForClassFields, /*isStatic*/ false);
|
||||
|
||||
// Only generate synthetic constructor when there are property initializers to move.
|
||||
if (!constructor && !some(properties)) {
|
||||
@@ -325,7 +326,6 @@ namespace ts {
|
||||
if (constructor) {
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor);
|
||||
}
|
||||
|
||||
// Add the property initializers. Transforms this:
|
||||
//
|
||||
// public x = 1;
|
||||
@@ -336,19 +336,16 @@ namespace ts {
|
||||
// this.x = 1;
|
||||
// }
|
||||
//
|
||||
if (constructor && constructor.body) {
|
||||
let parameterPropertyDeclarationCount = 0;
|
||||
for (let i = indexOfFirstStatement; i < constructor.body.statements.length; i++) {
|
||||
if (isParameterPropertyDeclaration(getOriginalNode(constructor.body.statements[i]), constructor)) {
|
||||
parameterPropertyDeclarationCount++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
if (constructor?.body) {
|
||||
let afterParameterProperties = findIndex(constructor.body.statements, s => !isParameterPropertyDeclaration(getOriginalNode(s), constructor), indexOfFirstStatement);
|
||||
if (afterParameterProperties === -1) {
|
||||
afterParameterProperties = constructor.body.statements.length;
|
||||
}
|
||||
if (parameterPropertyDeclarationCount > 0) {
|
||||
addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, indexOfFirstStatement, parameterPropertyDeclarationCount));
|
||||
indexOfFirstStatement += parameterPropertyDeclarationCount;
|
||||
if (afterParameterProperties > indexOfFirstStatement) {
|
||||
if (!useDefineForClassFields) {
|
||||
addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, indexOfFirstStatement, afterParameterProperties - indexOfFirstStatement));
|
||||
}
|
||||
indexOfFirstStatement = afterParameterProperties;
|
||||
}
|
||||
}
|
||||
addPropertyStatements(statements, properties, createThis());
|
||||
@@ -421,7 +418,9 @@ namespace ts {
|
||||
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name))
|
||||
: property.name;
|
||||
|
||||
const initializer = property.initializer || emitAssignment ? visitNode(property.initializer, visitor, isExpression) : createVoidZero();
|
||||
const initializer = property.initializer || emitAssignment ? visitNode(property.initializer, visitor, isExpression)
|
||||
: hasModifier(getOriginalNode(property), ModifierFlags.ParameterPropertyModifier) && isIdentifier(propertyName) ? propertyName
|
||||
: createVoidZero();
|
||||
if (emitAssignment) {
|
||||
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
|
||||
return createAssignment(memberAccess, initializer);
|
||||
|
||||
@@ -900,13 +900,13 @@ namespace ts {
|
||||
if (parametersWithPropertyAssignments) {
|
||||
for (const parameter of parametersWithPropertyAssignments) {
|
||||
if (isIdentifier(parameter.name)) {
|
||||
members.push(aggregateTransformFlags(createProperty(
|
||||
members.push(setOriginalNode(aggregateTransformFlags(createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
parameter.name,
|
||||
/*questionOrExclamationToken*/ undefined,
|
||||
/*type*/ undefined,
|
||||
/*initializer*/ undefined)));
|
||||
/*initializer*/ undefined)), parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user