@@ -641,7 +641,7 @@ namespace ts {
641641 }
642642 // declaration is after usage
643643 // can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
644- if (isUsedInFunctionOrNonStaticProperty (usage)) {
644+ if (isUsedInFunctionOrInstanceProperty (usage)) {
645645 return true;
646646 }
647647 const sourceFiles = host.getSourceFiles();
@@ -668,10 +668,12 @@ namespace ts {
668668 }
669669
670670
671- // declaration is after usage
672- // can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
671+ // declaration is after usage, but it can still be legal if usage is deferred:
672+ // 1. inside a function
673+ // 2. inside an instance property initializer, a reference to a non-instance property
673674 const container = getEnclosingBlockScopeContainer(declaration);
674- return isUsedInFunctionOrNonStaticProperty(usage, container);
675+ const isInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static);
676+ return isUsedInFunctionOrInstanceProperty(usage, isInstanceProperty, container);
675677
676678 function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
677679 const container = getEnclosingBlockScopeContainer(declaration);
@@ -700,7 +702,7 @@ namespace ts {
700702 return false;
701703 }
702704
703- function isUsedInFunctionOrNonStaticProperty (usage: Node, container?: Node): boolean {
705+ function isUsedInFunctionOrInstanceProperty (usage: Node, isDeclarationInstanceProperty?: boolean , container?: Node): boolean {
704706 let current = usage;
705707 while (current) {
706708 if (current === container) {
@@ -711,13 +713,13 @@ namespace ts {
711713 return true;
712714 }
713715
714- const initializerOfNonStaticProperty = current.parent &&
716+ const initializerOfInstanceProperty = current.parent &&
715717 current.parent.kind === SyntaxKind.PropertyDeclaration &&
716718 (getModifierFlags(current.parent) & ModifierFlags.Static) === 0 &&
717719 (<PropertyDeclaration>current.parent).initializer === current;
718720
719- if (initializerOfNonStaticProperty ) {
720- return true ;
721+ if (initializerOfInstanceProperty ) {
722+ return !isDeclarationInstanceProperty ;
721723 }
722724
723725 current = current.parent;
@@ -986,10 +988,10 @@ namespace ts {
986988 // interface bar {}
987989 // }
988990 // const foo/*1*/: foo/*2*/.bar;
989- // The foo at /*1*/ and /*2*/ will share same symbol with two meaning
990- // block - scope variable and namespace module. However, only when we
991+ // The foo at /*1*/ and /*2*/ will share same symbol with two meanings:
992+ // block-scoped variable and namespace module. However, only when we
991993 // try to resolve name in /*1*/ which is used in variable position,
992- // we want to check for block- scoped
994+ // we want to check for block-scoped
993995 if (meaning & SymbolFlags.BlockScopedVariable) {
994996 const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result);
995997 if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable) {
@@ -1013,7 +1015,7 @@ namespace ts {
10131015 return false;
10141016 }
10151017
1016- const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true);
1018+ const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ true);
10171019 let location = container;
10181020 while (location) {
10191021 if (isClassLike(location.parent)) {
@@ -12543,6 +12545,16 @@ namespace ts {
1254312545 }
1254412546 }
1254512547
12548+ function isInPropertyInitializer(node: Node): boolean {
12549+ while (node) {
12550+ if (node.parent && node.parent.kind === SyntaxKind.PropertyDeclaration && (node.parent as PropertyDeclaration).initializer === node) {
12551+ return true;
12552+ }
12553+ node = node.parent;
12554+ }
12555+ return false;
12556+ }
12557+
1254612558 function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
1254712559 const type = checkNonNullExpression(left);
1254812560 if (isTypeAny(type) || type === silentNeverType) {
@@ -12565,6 +12577,11 @@ namespace ts {
1256512577 }
1256612578 return unknownType;
1256712579 }
12580+ if (prop.valueDeclaration &&
12581+ isInPropertyInitializer(node) &&
12582+ !isBlockScopedNameDeclaredBeforeUse(prop.valueDeclaration, right)) {
12583+ error(right, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, right.text);
12584+ }
1256812585
1256912586 markPropertyAsReferenced(prop);
1257012587
0 commit comments