@@ -640,7 +640,7 @@ namespace ts {
640640 }
641641 // declaration is after usage
642642 // 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)) {
644644 return true;
645645 }
646646 const sourceFiles = host.getSourceFiles();
@@ -667,10 +667,12 @@ namespace ts {
667667 }
668668
669669
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
672673 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);
674676
675677 function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
676678 const container = getEnclosingBlockScopeContainer(declaration);
@@ -699,7 +701,7 @@ namespace ts {
699701 return false;
700702 }
701703
702- function isUsedInFunctionOrNonStaticProperty (usage: Node, container?: Node): boolean {
704+ function isUsedInFunctionOrInstanceProperty (usage: Node, isDeclarationInstanceProperty?: boolean , container?: Node): boolean {
703705 let current = usage;
704706 while (current) {
705707 if (current === container) {
@@ -710,13 +712,13 @@ namespace ts {
710712 return true;
711713 }
712714
713- const initializerOfNonStaticProperty = current.parent &&
715+ const initializerOfInstanceProperty = current.parent &&
714716 current.parent.kind === SyntaxKind.PropertyDeclaration &&
715717 (getModifierFlags(current.parent) & ModifierFlags.Static) === 0 &&
716718 (<PropertyDeclaration>current.parent).initializer === current;
717719
718- if (initializerOfNonStaticProperty ) {
719- return true ;
720+ if (initializerOfInstanceProperty ) {
721+ return !isDeclarationInstanceProperty ;
720722 }
721723
722724 current = current.parent;
@@ -985,10 +987,10 @@ namespace ts {
985987 // interface bar {}
986988 // }
987989 // 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
990992 // 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
992994 if (meaning & SymbolFlags.BlockScopedVariable) {
993995 const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result);
994
436F
td>996 if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable) {
@@ -1012,7 +1014,7 @@ namespace ts {
10121014 return false;
10131015 }
10141016
1015- const container = getThisContainer(errorLocation, /* includeArrowFunctions */ true);
1017+ const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ true);
10161018 let location = container;
10171019 while (location) {
10181020 if (isClassLike(location.parent)) {
@@ -3994,7 +3996,7 @@ namespace ts {
39943996 // A valid base type is any non-generic object type or inter
C851
section of non-generic
39953997 // object types.
39963998 function isValidBaseType(type: Type): boolean {
3997- return type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
3999+ return type.flags & ( TypeFlags.Object | TypeFlags.NonPrimitive) && !isGenericMappedType(type) ||
39984000 type.flags & TypeFlags.Intersection && !forEach((<IntersectionType>type).types, t => !isValidBaseType(t));
39994001 }
40004002
@@ -4932,7 +4934,7 @@ namespace ts {
49324934 }
49334935
49344936 function getApparentTypeOfIntersectionType(type: IntersectionType) {
4935- return type.resolvedIndexType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
4937+ return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
49364938 }
49374939
49384940 /**
@@ -4947,7 +4949,7 @@ namespace ts {
49474949 t.flags & TypeFlags.NumberLike ? globalNumberType :
49484950 t.flags & TypeFlags.BooleanLike ? globalBooleanType :
49494951 t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() :
4950- t.flags & TypeFlags.NonPrimitive ? globalObjectType :
4952+ t.flags & TypeFlags.NonPrimitive ? emptyObjectType :
49514953 t;
49524954 }
49534955
@@ -12546,6 +12548,16 @@ namespace ts {
1254612548 }
1254712549 }
1254812550
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+
1254912561 function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
1255012562 const type = checkNonNullExpression(left);
1255112563 if (isTypeAny(type) || type === silentNeverType) {
@@ -12568,6 +12580,11 @@ namespace ts {
1256812580 }
1256912581 return unknownType;
1257012582 }
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+ }
1257112588
1257212589 markPropertyAsReferenced(prop);
1257312590
0 commit comments