@@ -641,7 +641,7 @@ namespace ts {
641
641
}
642
642
// declaration is after usage
643
643
// 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)) {
645
645
return true;
646
646
}
647
647
const sourceFiles = host.getSourceFiles();
@@ -668,10 +668,12 @@ namespace ts {
668
668
}
669
669
670
670
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
673
674
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);
675
677
676
678
function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
677
679
const container = getEnclosingBlockScopeContainer(declaration);
@@ -700,7 +702,7 @@ namespace ts {
700
702
return false;
701
703
}
702
704
703
- function isUsedInFunctionOrNonStaticProperty (usage: Node, container?: Node): boolean {
705
+ function isUsedInFunctionOrInstanceProperty (usage: Node, isDeclarationInstanceProperty?: boolean , container?: Node): boolean {
704
706
let current = usage;
705
707
while (current) {
706
708
if (current === container) {
@@ -711,13 +713,13 @@ namespace ts {
711
713
return true;
712
714
}
713
715
714
- const initializerOfNonStaticProperty = current.parent &&
716
+ const initializerOfInstanceProperty = current.parent &&
715
717
current.parent.kind === SyntaxKind.PropertyDeclaration &&
716
718
(getModifierFlags(current.parent) & ModifierFlags.Static) === 0 &&
717
719
(<PropertyDeclaration>current.parent).initializer === current;
718
720
719
- if (initializerOfNonStaticProperty ) {
720
- return true ;
721
+ if (initializerOfInstanceProperty ) {
722
+ return !isDeclarationInstanceProperty ;
721
723
}
722
724
723
725
current = current.parent;
@@ -986,10 +988,10 @@ namespace ts {
986
988
// interface bar {}
987
989
// }
988
990
// 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
991
993
// 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
993
995
if (meaning & SymbolFlags.BlockScopedVariable) {
994
996
const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result);
995
997
if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable) {
@@ -1013,7 +1015,7 @@ namespace ts {
1013
1015
return false;
1014
1016
}
1015
1017
1016
- const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true);
1018
+ const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ true);
1017
1019
let location = container;
1018
1020
while (location) {
1019
1021
if (isClassLike(location.parent)) {
@@ -12543,6 +12545,16 @@ namespace ts {
12543
12545
}
12544
12546
}
12545
12547
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
+
12546
12558
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
12547
12559
const type = checkNonNullExpression(left);
12548
12560
if (isTypeAny(type) || type === silentNeverType) {
@@ -12565,6 +12577,11 @@ namespace ts {
12565
12577
}
12566
12578
return unknownType;
12567
12579
}
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
+ }
12568
12585
12569
12586
markPropertyAsReferenced(prop);
12570
12587
0 commit comments