mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
fix use-before-init error when targeting ES2022 (#55028)
This commit is contained in:
+13
-11
@@ -274,6 +274,7 @@ import {
|
||||
getEmitModuleKind,
|
||||
getEmitModuleResolutionKind,
|
||||
getEmitScriptTarget,
|
||||
getEmitStandardClassFields,
|
||||
getEnclosingBlockScopeContainer,
|
||||
getEnclosingContainer,
|
||||
getEntityNameFromTypeNode,
|
||||
@@ -1437,6 +1438,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
var moduleKind = getEmitModuleKind(compilerOptions);
|
||||
var legacyDecorators = !!compilerOptions.experimentalDecorators;
|
||||
var useDefineForClassFields = getUseDefineForClassFields(compilerOptions);
|
||||
var emitStandardClassFields = getEmitStandardClassFields(compilerOptions);
|
||||
var allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions);
|
||||
var strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
|
||||
var strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes");
|
||||
@@ -2785,8 +2787,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ false);
|
||||
}
|
||||
else if (isParameterPropertyDeclaration(declaration, declaration.parent)) {
|
||||
// foo = this.bar is illegal in esnext+useDefineForClassFields when bar is a parameter property
|
||||
return !(getEmitScriptTarget(compilerOptions) === ScriptTarget.ESNext && useDefineForClassFields
|
||||
// foo = this.bar is illegal in emitStandardClassFields when bar is a parameter property
|
||||
return !(emitStandardClassFields
|
||||
&& getContainingClass(declaration) === getContainingClass(usage)
|
||||
&& isUsedInFunctionOrInstanceProperty(usage, declaration));
|
||||
}
|
||||
@@ -2798,7 +2800,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// 1. inside an export specifier
|
||||
// 2. inside a function
|
||||
// 3. inside an instance property initializer, a reference to a non-instance property
|
||||
// (except when target: "esnext" and useDefineForClassFields: true and the reference is to a parameter property)
|
||||
// (except when emitStandardClassFields: true and the reference is to a parameter property)
|
||||
// 4. inside a static property initializer, a reference to a static method in the same class
|
||||
// 5. inside a TS export= declaration (since we will move the export statement during emit to avoid TDZ)
|
||||
// or if usage is in a type context:
|
||||
@@ -2817,7 +2819,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return true;
|
||||
}
|
||||
if (isUsedInFunctionOrInstanceProperty(usage, declaration)) {
|
||||
if (getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 && useDefineForClassFields
|
||||
if (emitStandardClassFields
|
||||
&& getContainingClass(declaration)
|
||||
&& (isPropertyDeclaration(declaration) || isParameterPropertyDeclaration(declaration, declaration.parent))) {
|
||||
return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ true);
|
||||
@@ -2974,7 +2976,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
// static properties in classes introduce temporary variables
|
||||
if (hasStaticModifier(node)) {
|
||||
return target < ScriptTarget.ESNext || !useDefineForClassFields;
|
||||
return !emitStandardClassFields;
|
||||
}
|
||||
return requiresScopeChangeWorker((node as PropertyDeclaration).name);
|
||||
default:
|
||||
@@ -3392,10 +3394,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// 1. When result is undefined, after checking for a missing "this."
|
||||
// 2. When result is defined
|
||||
function checkAndReportErrorForInvalidInitializer() {
|
||||
if (propertyWithInvalidInitializer && !(useDefineForClassFields && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022)) {
|
||||
if (propertyWithInvalidInitializer && !emitStandardClassFields) {
|
||||
// We have a match, but the reference occurred within a property initializer and the identifier also binds
|
||||
// to a local variable in the constructor where the code will be emitted. Note that this is actually allowed
|
||||
// with ESNext+useDefineForClassFields because the scope semantics are different.
|
||||
// with emitStandardClassFields because the scope semantics are different.
|
||||
error(errorLocation,
|
||||
errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos)
|
||||
? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor
|
||||
@@ -31739,7 +31741,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
&& !(isAccessExpression(node) && isAccessExpression(node.expression))
|
||||
&& !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)
|
||||
&& !(isMethodDeclaration(valueDeclaration) && getCombinedModifierFlagsCached(valueDeclaration) & ModifierFlags.Static)
|
||||
&& (compilerOptions.useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) {
|
||||
&& (useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) {
|
||||
diagnosticMessage = error(right, Diagnostics.Property_0_is_used_before_its_initialization, declarationName);
|
||||
}
|
||||
else if (valueDeclaration.kind === SyntaxKind.ClassDeclaration &&
|
||||
@@ -38453,7 +38455,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
case "length":
|
||||
case "caller":
|
||||
case "arguments":
|
||||
if (compilerOptions.useDefineForClassFields) {
|
||||
if (useDefineForClassFields) {
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
@@ -38658,7 +38660,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// or the containing class declares instance member variables with initializers.
|
||||
|
||||
const superCallShouldBeRootLevel =
|
||||
(getEmitScriptTarget(compilerOptions) !== ScriptTarget.ESNext || !useDefineForClassFields) &&
|
||||
!emitStandardClassFields &&
|
||||
(some((node.parent as ClassDeclaration).members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) ||
|
||||
some(node.parameters, p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier)));
|
||||
|
||||
@@ -42935,7 +42937,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
!legacyDecorators && languageVersion < ScriptTarget.ESNext &&
|
||||
classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node);
|
||||
const willTransformPrivateElementsOrClassStaticBlocks = languageVersion <= ScriptTarget.ES2022;
|
||||
const willTransformInitializers = !useDefineForClassFields || languageVersion < ScriptTarget.ES2022;
|
||||
const willTransformInitializers = !emitStandardClassFields;
|
||||
if (willTransformStaticElementsOfDecoratedClass || willTransformPrivateElementsOrClassStaticBlocks) {
|
||||
for (const member of node.members) {
|
||||
if (willTransformStaticElementsOfDecoratedClass && classElementOrClassElementParameterIsDecorated(/*useLegacyDecorators*/ false, member, node)) {
|
||||
|
||||
@@ -8666,6 +8666,11 @@ export function getUseDefineForClassFields(compilerOptions: CompilerOptions): bo
|
||||
return compilerOptions.useDefineForClassFields === undefined ? getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 : compilerOptions.useDefineForClassFields;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getEmitStandardClassFields(compilerOptions: CompilerOptions) {
|
||||
return compilerOptions.useDefineForClassFields !== false && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean {
|
||||
return optionsHaveChanges(oldOptions, newOptions, semanticDiagnosticsOptionDeclarations);
|
||||
|
||||
Reference in New Issue
Block a user