Skip to content

Commit feb0fb6

Browse files
committed
Everything works so far
Need to test properties initialised in constructor
1 parent 70a15bd commit feb0fb6

12 files changed

+297
-51
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29206,6 +29206,11 @@ namespace ts {
2920629206
}
2920729207
}
2920829208

29209+
function getClassOrInterfaceDeclarationsOfSymbol(symbol: Symbol) {
29210+
return filter(symbol.declarations, (d: Declaration): d is ClassDeclaration | InterfaceDeclaration =>
29211+
d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration);
29212+
}
29213+
2920929214
function areTypeParametersIdentical(declarations: readonly (ClassDeclaration | InterfaceDeclaration)[], targetParameters: TypeParameter[]) {
2921029215
const maxTypeArgumentCount = length(targetParameters);
2921129216
const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters);
@@ -29299,6 +29304,7 @@ namespace ts {
2929929304
checkClassForStaticPropertyNameConflicts(node);
2930029305
}
2930129306

29307+
let baseType: BaseType | undefined;
2930229308
const baseTypeNode = getEffectiveBaseTypeNode(node);
2930329309
if (baseTypeNode) {
2930429310
if (languageVersion < ScriptTarget.ES2015) {
@@ -29312,7 +29318,7 @@ namespace ts {
2931229318

2931329319
const baseTypes = getBaseTypes(type);
2931429320
if (baseTypes.length && produceDiagnostics) {
29315-
const baseType = baseTypes[0];
29321+
baseType = baseTypes[0];
2931629322
const baseConstructorType = getBaseConstructorTypeOfClass(type);
2931729323
const staticBaseType = getApparentType(baseConstructorType);
2931829324
checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
@@ -29352,6 +29358,7 @@ namespace ts {
2935229358
checkKindsOfPropertyMemberOverrides(type, baseType);
2935329359
}
2935429360
}
29361+
checkAmbientPropertyMemberOverrides(type, baseType);
2935529362

2935629363
const implementedTypeNodes = getClassImplementsHeritageClauseElements(node);
2935729364
if (implementedTypeNodes) {
@@ -29437,11 +29444,6 @@ namespace ts {
2943729444
return getCheckFlags(s) & CheckFlags.Instantiated ? (<TransientSymbol>s).target! : s;
2943829445
}
2943929446

29440-
function getClassOrInterfaceDeclarationsOfSymbol(symbol: Symbol) {
29441-
return filter(symbol.declarations, (d: Declaration): d is ClassDeclaration | InterfaceDeclaration =>
29442-
d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration);
29443-
}
29444-
2944529447
/**
2944629448
* TypeScript 1.0 spec (April 2014): 8.2.3
2944729449
* A derived class inherits all members from its base class it doesn't override.
@@ -29529,11 +29531,6 @@ namespace ts {
2952929531
}
2953029532
continue;
2953129533
}
29532-
if (derivedDeclarationFlags & ModifiersFlags.Ambient) {
29533-
const errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_so_extended_class_2_must_provide_an_initializer_with_this_override;
29534-
error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type));
29535-
continue;
29536-
}
2953729534

2953829535
let errorMessage: DiagnosticMessage;
2953929536
if (isPrototypeProperty(base)) {
@@ -29556,6 +29553,20 @@ namespace ts {
2955629553
}
2955729554
}
2955829555

29556+
function checkAmbientPropertyMemberOverrides(type: Type, baseType?: Type) {
29557+
for (const derivedProperty of getPropertiesOfType(type)) {
29558+
const derived = getTargetSymbol(derivedProperty);
29559+
if (derived.flags & SymbolFlags.Prototype) {
29560+
continue;
29561+
}
29562+
const base = baseType && getPropertyOfObjectType(baseType, derived.escapedName);
29563+
if (!base && getDeclarationModifierFlagsFromSymbol(derived) & ModifierFlags.Ambient) {
29564+
const errorMessage = Diagnostics.Ambient_property_declarations_must_override_a_property_in_a_base_class;
29565+
error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage);
29566+
}
29567+
}
29568+
}
29569+
2955929570
function checkInheritedPropertiesAreIdentical(type: InterfaceType, typeNode: Node): boolean {
2956029571
const baseTypes = getBaseTypes(type);
2956129572
if (baseTypes.length < 2) {
@@ -29599,6 +29610,9 @@ namespace ts {
2959929610
}
2960029611
const constructor = findConstructorDeclaration(node);
2960129612
for (const member of node.members) {
29613+
if (getModifierFlags(member) & ModifierFlags.Ambient) {
29614+
continue;
29615+
}
2960229616
if (isInstancePropertyWithoutInitializer(member)) {
2960329617
const propName = (<PropertyDeclaration>member).name;
2960429618
if (isIdentifier(propName)) {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,10 @@
22082208
"category": "Error",
22092209
"code": 2610
22102210
},
2211+
"Ambient property declarations must override a property in a base class.": {
2212+
"category": "Error",
2213+
"code": 2611
2214+
},
22112215
"Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {
22122216
"category": "Error",
22132217
"code": 2649

tests/baselines/reference/classExpressionPropertyModifiers.errors.txt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
tests/cases/compiler/classExpressionPropertyModifiers.ts(2,5): error TS1031: 'declare' modifier cannot appear on a class element.
1+
tests/cases/compiler/classExpressionPropertyModifiers.ts(2,13): error TS2611: Ambient property declarations must override a property in a base class.
2+
tests/cases/compiler/classExpressionPropertyModifiers.ts(2,36): error TS1039: Initializers are not allowed in ambient contexts.
23
tests/cases/compiler/classExpressionPropertyModifiers.ts(3,5): error TS1031: 'export' modifier cannot appear on a class element.
34

45

5-
==== tests/cases/compiler/classExpressionPropertyModifiers.ts (2 errors) ====
6+
==== tests/cases/compiler/classExpressionPropertyModifiers.ts (3 errors) ====
67
const a = class Cat {
78
declare [Symbol.toStringTag] = "uh";
8-
~~~~~~~
9-
!!! error TS1031: 'declare' modifier cannot appear on a class element.
9+
~~~~~~~~~~~~~~~~~~~~
10+
!!! error TS2611: Ambient property declarations must override a property in a base class.
11+
~~~~
12+
!!! error TS1039: Initializers are not allowed in ambient contexts.
1013
export foo = 1;
1114
~~~~~~
1215
!!! error TS1031: 'export' modifier cannot appear on a class element.
Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,72 @@
1-
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(5,5): error TS2610: Class 'A' defines instance member property 'property', so extended class 'B' must provide an initializer with this override.
2-
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(14,5): error TS2610: Class 'C' defines instance member property 'p', so extended class 'D' must provide an initializer with this override.
1+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(6,5): error TS2610: Class 'A' defines instance member property 'property', so extended class 'B' must provide an initializer with this override.
2+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(15,5): error TS1031: 'declare' modifier cannot appear on a class element.
3+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(16,13): error TS2611: Ambient property declarations must override a property in a base class.
4+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(17,24): error TS1039: Initializers are not allowed in ambient contexts.
5+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(20,13): error TS2611: Ambient property declarations must override a property in a base class.
6+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(24,5): error TS2564: Property 'p' has no initializer and is not definitely assigned in the constructor.
7+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(27,5): error TS2564: Property 'p' has no initializer and is not definitely assigned in the constructor.
8+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(27,5): error TS2610: Class 'C' defines instance member property 'p', so extended class 'D' must provide an initializer with this override.
9+
tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts(39,5): error TS2610: Class 'E' defines instance member property 'p1', so extended class 'F' must provide an initializer with this override.
310

411

5-
==== tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts (2 errors) ====
12+
==== tests/cases/conformance/classes/propertyMemberDeclarations/derivedUninitializedPropertyDeclaration.ts (9 errors) ====
613
class A {
714
property = 'x';
15+
m() { return 1 }
816
}
917
class B extends A {
10-
property; // error
18+
property: any; // error
1119
~~~~~~~~
1220
!!! error TS2610: Class 'A' defines instance member property 'property', so extended class 'B' must provide an initializer with this override.
1321
}
1422
class BD extends A {
15-
declare property; // still has implicit any
23+
declare property: any; // ok because it's implicitly initialised
1624
}
25+
class BDBang extends A {
26+
declare property!: any; // doesn't need !, but is still allowed
27+
}
28+
class BOther extends A {
29+
declare m() { return 2 } // not allowed on methods
30+
~~~~~~~
31+
!!! error TS1031: 'declare' modifier cannot appear on a class element.
32+
declare nonce: any; // only allowed when exists in base
33+
~~~~~
34+
!!! error TS2611: Ambient property declarations must override a property in a base class.
35+
declare property = 'y' // initialiser not allowed with declare
36+
~~~
37+
!!! error TS1039: Initializers are not allowed in ambient contexts.
38+
}
39+
class U {
40+
declare nonce: any; // ambient declaration only allowed when an override
41+
~~~~~
42+
!!! error TS2611: Ambient property declarations must override a property in a base class.
43+
}
44+
1745
class C {
1846
p: string;
47+
~
48+
!!! error TS2564: Property 'p' has no initializer and is not definitely assigned in the constructor.
1949
}
2050
class D extends C {
2151
p: 'hi'; // error
2252
~
53+
!!! error TS2564: Property 'p' has no initializer and is not definitely assigned in the constructor.
54+
~
2355
!!! error TS2610: Class 'C' defines instance member property 'p', so extended class 'D' must provide an initializer with this override.
2456
}
2557
class DD extends C {
2658
declare p: 'bye'; // ok
2759
}
60+
61+
62+
declare class E {
63+
p1: string
64+
p2: string
65+
}
66+
class F extends E {
67+
p1!: 'z'
68+
~~
69+
!!! error TS2610: Class 'E' defines instance member property 'p1', so extended class 'F' must provide an initializer with this override.
70+
declare p2: 'alpha'
71+
}
2872

tests/baselines/reference/derivedUninitializedPropertyDeclaration.js

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
//// [derivedUninitializedPropertyDeclaration.ts]
22
class A {
33
property = 'x';
4+
m() { return 1 }
45
}
56
class B extends A {
6-
property; // error
7+
property: any; // error
78
}
89
class BD extends A {
9-
declare property; // still has implicit any
10+
declare property: any; // ok because it's implicitly initialised
1011
}
12+
class BDBang extends A {
13+
declare property!: any; // doesn't need !, but is still allowed
14+
}
15+
class BOther extends A {
16+
declare m() { return 2 } // not allowed on methods
17+
declare nonce: any; // only allowed when exists in base
18+
declare property = 'y' // initialiser not allowed with declare
19+
}
20+
class U {
21+
declare nonce: any; // ambient declaration only allowed when an override
22+
}
23+
1124
class C {
1225
p: string;
1326
}
@@ -17,9 +30,20 @@ class D extends C {
1730
class DD extends C {
1831
declare p: 'bye'; // ok
1932
}
33+
34+
35+
declare class E {
36+
p1: string
37+
p2: string
38+
}
39+
class F extends E {
40+
p1!: 'z'
41+
declare p2: 'alpha'
42+
}
2043

2144

2245
//// [derivedUninitializedPropertyDeclaration.js]
46+
"use strict";
2347
var __extends = (this && this.__extends) || (function () {
2448
var extendStatics = function (d, b) {
2549
extendStatics = Object.setPrototypeOf ||
@@ -37,6 +61,7 @@ var A = /** @class */ (function () {
3761
function A() {
3862
this.property = 'x';
3963
}
64+
A.prototype.m = function () { return 1; };
4065
return A;
4166
}());
4267
var B = /** @class */ (function (_super) {
@@ -53,6 +78,28 @@ var BD = /** @class */ (function (_super) {
5378
}
5479
return BD;
5580
}(A));
81+
var BDBang = /** @class */ (function (_super) {
82+
__extends(BDBang, _super);
83+
function BDBang() {
84+
return _super !== null && _super.apply(this, arguments) || this;
85+
}
86+
return BDBang;
87+
}(A));
88+
var BOther = /** @class */ (function (_super) {
89+
__extends(BOther, _super);
90+
function BOther() {
91+
var _this = _super !== null && _super.apply(this, arguments) || this;
92+
_this.property = 'y'; // initialiser not allowed with declare
93+
return _this;
94+
}
95+
BOther.prototype.m = function () { return 2; }; // not allowed on methods
96+
return BOther;
97+
}(A));
98+
var U = /** @class */ (function () {
99+
function U() {
100+
}
101+
return U;
102+
}());
56103
var C = /** @class */ (function () {
57104
function C() {
58105
}
@@ -72,3 +119,10 @@ var DD = /** @class */ (function (_super) {
72119
}
73120
return DD;
74121
}(C));
122+
var F = /** @class */ (function (_super) {
123+
__extends(F, _super);
124+
function F() {
125+
return _super !== null && _super.apply(this, arguments) || this;
126+
}
127+
return F;
128+
}(E));

0 commit comments

Comments
 (0)