@@ -640,7 +640,7 @@ namespace ts {
640
640
}
641
641
// declaration is after usage
642
642
// can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
643
- if (isUsedInFunctionOrNonStaticProperty (usage)) {
643
+ if (isUsedInFunctionOrInstanceProperty (usage)) {
644
644
return true;
645
645
}
646
646
const sourceFiles = host.getSourceFiles();
@@ -667,10 +667,12 @@ namespace ts {
667
667
}
668
668
669
669
670
- // declaration is after usage
671
- // can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
670
+ // declaration is after usage, but it can still be legal if usage is deferred:
671
+ // 1. inside a function
672
+ // 2. inside an instance property initializer, a reference to a non-instance property
672
673
const container = getEnclosingBlockScopeContainer(declaration);
673
- return isUsedInFunctionOrNonStaticProperty(usage, container);
674
+ const isInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static);
675
+ return isUsedInFunctionOrInstanceProperty(usage, isInstanceProperty, container);
674
676
675
677
function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
676
678
const container = getEnclosingBlockScopeContainer(declaration);
@@ -699,7 +701,7 @@ namespace ts {
699
701
return false;
700
702
}
701
703
702
- function isUsedInFunctionOrNonStaticProperty (usage: Node, container?: Node): boolean {
704
+ function isUsedInFunctionOrInstanceProperty (usage: Node, isDeclarationInstanceProperty?: boolean , container?: Node): boolean {
703
705
let current = usage;
704
706
while (current) {
705
707
if (current === container) {
@@ -710,13 +712,13 @@ namespace ts {
710
712
return true;
711
713
}
712
714
713
- const initializerOfNonStaticProperty = current.parent &&
715
+ const initializerOfInstanceProperty = current.parent &&
714
716
current.parent.kind === SyntaxKind.PropertyDeclaration &&
715
717
(getModifierFlags(current.parent) & ModifierFlags.Static) === 0 &&
716
718
(<PropertyDeclaration>current.parent).initializer === current;
717
719
718
- if (initializerOfNonStaticProperty ) {
719
- return true ;
720
+ if (initializerOfInstanceProperty ) {
721
+ return !isDeclarationInstanceProperty ;
720
722
}
721
723
722
724
current = current.parent;
@@ -985,10 +987,10 @@ namespace ts {
985
987
// interface bar {}
986
988
// }
987
989
// const foo/*1*/: foo/*2*/.bar;
988
- // The foo at /*1*/ and /*2*/ will share same symbol with two meaning
989
- // block - scope variable and namespace module. However, only when we
990
+ // The foo at /*1*/ and /*2*/ will share same symbol with two meanings:
991
+ // block-scoped variable and namespace module. However, only when we
990
992
// try to resolve name in /*1*/ which is used in variable position,
991
- // we want to check for block- scoped
993
+ // we want to check for block-scoped
992
994
if (meaning & SymbolFlags.BlockScopedVariable) {
993
995
const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result);
994
996
if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable) {
@@ -1012,7 +1014,7 @@ namespace ts {
1012
1014
return false;
1013
1015
}
1014
1016
1015
- const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true);
1017
+ const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ true);
1016
1018
let location = container;
1017
1019
while (location) {
1018
1020
if (isClassLike(location.parent)) {
@@ -3994,7 +3996,7 @@ namespace ts {
3994
3996
// A valid base type is any non-generic object type or intersection of non-generic
3995
3997
// object types.
3996
3998
function isValidBaseType(type: Type): boolean {
3997
- return type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
3999
+ return type.flags & ( TypeFlags.Object | TypeFlags.NonPrimitive) && !isGenericMappedType(type) ||
3998
4000
type.flags & TypeFlags.Intersection && !forEach((<IntersectionType>type).types, t => !isValidBaseType(t));
3999
4001
}
4000
4002
@@ -4932,7 +4934,7 @@ namespace ts {
4932
4934
}
4933
4935
4934
4936
function getApparentTypeOfIntersectionType(type: IntersectionType) {
4935
- return type.resolvedIndexType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
4937
+ return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
4936
4938
}
4937
4939
4938
4940
/**
@@ -4947,7 +4949,7 @@ namespace ts {
4947
4949
t.flags & TypeFlags.NumberLike ? globalNumberType :
4948
4950
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
4949
4951
t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() :
4950
- t.flags & TypeFlags.NonPrimitive ? globalObjectType :
4952
+ t.flags & TypeFlags.NonPrimitive ? emptyObjectType :
4951
4953
t;
4952
4954
}
4953
4955
@@ -12546,6 +12548,16 @@ namespace ts {
12546
12548
}
12547
12549
}
12548
12550
12551
+ function isInPropertyInitializer(node: Node): boolean {
12552
+ while (node) {
12553
+ if (node.parent && node.parent.kind === SyntaxKind.PropertyDeclaration && (node.parent as PropertyDeclaration).initializer === node) {
12554
+ return true;
12555
+ }
12556
+ node = node.parent;
12557
+ }
12558
+ return false;
12559
+ }
12560
+
12549
12561
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
12550
12562
const type = checkNonNullExpression(left);
12551
12563
if (isTypeAny(type) || type === silentNeverType) {
@@ -12568,6 +12580,11 @@ namespace ts {
12568
12580
}
12569
12581
return unknownType;
12570
12582
}
12583
+ if (prop.valueDeclaration &&
12584
+ isInPropertyInitializer(node) &&
12585
+ !isBlockScopedNameDeclaredBeforeUse(prop.valueDeclaration, right)) {
12586
+ error(right, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, right.text);
12587
+ }
12571
12588
12572
12589
markPropertyAsReferenced(prop);
12573
12590
0 commit comments