Skip to content

Commit d770947

Browse files
author
andy-ms
committed
Respond to PR comments
1 parent 1a772f9 commit d770947

File tree

6 files changed

+72
-114
lines changed

6 files changed

+72
-114
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14674,34 +14674,31 @@ namespace ts {
1467414674
}
1467514675
}
1467614676

14677+
/**
14678+
* It's possible that "prop.valueDeclaration" is a local declaration, but the property was also declared in a superclass.
14679+
* In that case we won't consider it used before its declaration, because it gets its value from the superclass' declaration.
14680+
*/
1467714681
function isPropertyDeclaredInAncestorClass(prop: Symbol): boolean {
14678-
// It's possible that "prop.valueDeclaration" is a local declaration, but the property was also declared in a superclass.
14679-
// In that case we won't consider it used before its declaration, because it gets its value from the superclass' declaration.
14680-
let classSymbol = prop.parent;
14682+
let classType = getTypeOfSymbol(prop.parent) as InterfaceType;
1468114683
while (true) {
14682-
classSymbol = getSuperClass(classSymbol);
14683-
if (!classSymbol) {
14684+
classType = getSuperClass(classType);
14685+
if (!classType) {
1468414686
return false;
1468514687
}
14686-
const superProperty = classSymbol.members.get(prop.escapedName);
14688+
const superProperty = getPropertyOfType(classType, prop.escapedName);
1468714689
if (superProperty && superProperty.valueDeclaration) {
1468814690
return true;
1468914691
}
1469014692
}
1469114693
}
1469214694

14693-
// TODO: there must be a better way of doing this
14694-
function getSuperClass(classSymbol: Symbol): Symbol | undefined {
14695-
const classDecl = classSymbol.valueDeclaration;
14696-
if (!isClassLike(classDecl)) {
14697-
return undefined;
14698-
}
14699-
const superClassExpression = getClassExtendsHeritageClauseElement(classDecl);
14700-
if (!superClassExpression) {
14695+
function getSuperClass(classType: InterfaceType): InterfaceType | undefined {
14696+
const x = getBaseTypes(classType);
14697+
if (x.length === 0) {
1470114698
return undefined;
1470214699
}
14703-
const superClassSymbol = getSymbolAtLocation(superClassExpression.expression);
14704-
return superClassSymbol.flags & SymbolFlags.Class ? superClassSymbol : undefined;
14700+
Debug.assert(x.length === 1);
14701+
return x[0] as InterfaceType;
1470514702
}
1470614703

1470714704
function reportNonexistentProperty(propNode: Identifier, containingType: Type) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
tests/cases/compiler/useBeforeDeclaration_superClass.ts(25,18): error TS2448: Block-scoped variable 'x' used before its declaration.
2+
3+
4+
==== tests/cases/compiler/useBeforeDeclaration_superClass.ts (1 errors) ====
5+
class C {
6+
x = 0;
7+
}
8+
class D extends C {
9+
// Not an error -- this will access the parent's initialized value for `x`, not the one on the child.
10+
old_x = this.x;
11+
x = 1;
12+
}
13+
14+
// Test that it works on chains of classes
15+
class X {
16+
x = 0;
17+
}
18+
class Y extends X {}
19+
class Z extends Y {
20+
old_x = this.x;
21+
x = 1;
22+
}
23+
24+
// Interface doesn't count
25+
interface I {
26+
x: number;
27+
}
28+
class J implements I {
29+
old_x = this.x;
30+
~
31+
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
32+
x = 1;
33+
}
34+

tests/baselines/reference/useBeforeDeclaration_superClass.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ class Z extends Y {
1717
old_x = this.x;
1818
x = 1;
1919
}
20+
21+
// Interface doesn't count
22+
interface I {
23+
x: number;
24+
}
25+
class J implements I {
26+
old_x = this.x;
27+
x = 1;
28+
}
2029

2130

2231
//// [useBeforeDeclaration_superClass.js]
@@ -71,3 +80,10 @@ var Z = /** @class */ (function (_super) {
7180
}
7281
return Z;
7382
}(Y));
83+
var J = /** @class */ (function () {
84+
function J() {
85+
this.old_x = this.x;
86+
this.x = 1;
87+
}
88+
return J;
89+
}());

tests/baselines/reference/useBeforeDeclaration_superClass.symbols

Lines changed: 0 additions & 47 deletions
This file was deleted.

tests/baselines/reference/useBeforeDeclaration_superClass.types

Lines changed: 0 additions & 51 deletions
This file was deleted.

tests/cases/compiler/useBeforeDeclaration_superClass.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,12 @@ class Z extends Y {
1616
old_x = this.x;
1717
x = 1;
1818
}
19+
20+
// Interface doesn't count
21+
interface I {
22+
x: number;
23+
}
24+
class J implements I {
25+
old_x = this.x;
26+
x = 1;
27+
}

0 commit comments

Comments
 (0)