Skip to content

Commit 899d512

Browse files
authored
Merge pull request #12065 from about-code/master
Fixing #442: Impossible to define static 'length' function on class
2 parents 65ef51d + 9b217e3 commit 899d512

10 files changed

+1020
-52
lines changed

src/compiler/checker.ts

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,24 +2171,25 @@ namespace ts {
21712171
return type.flags & TypeFlags.StringLiteral ? `"${escapeString((<LiteralType>type).text)}"` : (<LiteralType>type).text;
21722172
}
21732173

2174-
function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
21752174

2176-
function getNameOfSymbol(symbol: Symbol): string {
2177-
if (symbol.declarations && symbol.declarations.length) {
2178-
const declaration = symbol.declarations[0];
2179-
if (declaration.name) {
2180-
return declarationNameToString(declaration.name);
2181-
}
2182-
switch (declaration.kind) {
2183-
case SyntaxKind.ClassExpression:
2184-
return "(Anonymous class)";
2185-
case SyntaxKind.FunctionExpression:
2186-
case SyntaxKind.ArrowFunction:
2187-
return "(Anonymous function)";
2188-
}
2175+
function getNameOfSymbol(symbol: Symbol): string {
2176+
if (symbol.declarations && symbol.declarations.length) {
2177+
const declaration = symbol.declarations[0];
2178+
if (declaration.name) {
2179+
return declarationNameToString(declaration.name);
2180+
}
2181+
switch (declaration.kind) {
2182+
case SyntaxKind.ClassExpression:
2183+
return "(Anonymous class)";
2184+
case SyntaxKind.FunctionExpression:
2185+
case SyntaxKind.ArrowFunction:
2186+
return "(Anonymous function)";
21892187
}
2190-
return symbol.name;
21912188
}
2189+
return symbol.name;
2190+
}
2191+
2192+
function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
21922193

21932194
/**
21942195
* Writes only the name of the symbol out to the writer. Uses the original source text
@@ -15680,7 +15681,7 @@ namespace ts {
1568015681
}
1568115682
}
1568215683
else {
15683-
const isStatic = forEach(member.modifiers, m => m.kind === SyntaxKind.StaticKeyword);
15684+
const isStatic = getModifierFlags(member) & ModifierFlags.Static;
1568415685
const names = isStatic ? staticNames : instanceNames;
1568515686

1568615687
const memberName = member.name && getPropertyNameForPropertyNameNode(member.name);
@@ -15718,6 +15719,38 @@ namespace ts {
1571815719
}
1571915720
}
1572015721

15722+
/**
15723+
* Static members being set on a constructor function may conflict with built-in properties
15724+
* of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable
15725+
* built-in properties. This check issues a transpile error when a class has a static
15726+
* member with the same name as a non-writable built-in property.
15727+
*
15728+
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.3
15729+
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5
15730+
* @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor
15731+
* @see http://www.ecma-international.org/ecma-262/6.0/#sec-function-instances
15732+
*/
15733+
function checkClassForStaticPropertyNameConflicts(node: ClassLikeDeclaration) {
15734+
for (const member of node.members) {
15735+
const memberNameNode = member.name;
15736+
const isStatic = getModifierFlags(member) & ModifierFlags.Static;
15737+
if (isStatic && memberNameNode) {
15738+
const memberName = getPropertyNameForPropertyNameNode(memberNameNode);
15739+
switch (memberName) {
15740+
case "name":
15741+
case "length":
15742+
case "caller":
15743+
case "arguments":
15744+
case "prototype":
15745+
const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1;
15746+
const className = getNameOfSymbol(getSymbolOfNode(node));
15747+
error(memberNameNode, message, memberName, className);
15748+
break;
15749+
}
15750+
}
15751+
}
15752+
}
15753+
1572115754
function checkObjectTypeForDuplicateDeclarations(node: TypeLiteralNode | InterfaceDeclaration) {
1572215755
const names = createMap<boolean>();
1572315756
for (const member of node.members) {
@@ -18291,6 +18324,7 @@ namespace ts {
1829118324
const staticType = <ObjectType>getTypeOfSymbol(symbol);
1829218325
checkTypeParameterListsIdentical(node, symbol);
1829318326
checkClassForDuplicateDeclarations(node);
18327+
checkClassForStaticPropertyNameConflicts(node);
1829418328

1829518329
const baseTypeNode = getClassExtendsHeritageClauseElement(node);
1829618330
if (baseTypeNode) {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,10 @@
20152015
"category": "Error",
20162016
"code": 2698
20172017
},
2018+
"Static property '{0}' conflicts with built-in property 'Function.{0}' of constructor function '{1}'.": {
2019+
"category": "Error",
2020+
"code": 2699
2021+
},
20182022
"Rest types may only be created from object types.": {
20192023
"category": "Error",
20202024
"code": 2700
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedPrototype.ts(3,12): error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'C'.
2+
3+
4+
==== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedPrototype.ts (1 errors) ====
5+
class C {
6+
prototype: number; // ok
7+
static prototype: C; // error
8+
~~~~~~~~~
9+
!!! error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'C'.
10+
}

tests/baselines/reference/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.errors.txt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,43 @@
11
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(12,1): error TS2322: Type 'C' is not assignable to type 'A'.
2-
Property 'name' is missing in type 'C'.
2+
Property 'prop' is missing in type 'C'.
33
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(13,1): error TS2322: Type 'typeof B' is not assignable to type 'A'.
4-
Property 'name' is missing in type 'typeof B'.
4+
Property 'prop' is missing in type 'typeof B'.
55
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(16,5): error TS2322: Type 'C' is not assignable to type 'B'.
6-
Property 'name' is missing in type 'C'.
6+
Property 'prop' is missing in type 'C'.
77
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(17,1): error TS2322: Type 'typeof B' is not assignable to type 'B'.
8-
Property 'name' is missing in type 'typeof B'.
8+
Property 'prop' is missing in type 'typeof B'.
99

1010

1111
==== tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts (4 errors) ====
1212
interface A {
13-
name();
13+
prop();
1414
}
1515
class B {
16-
public name() { }
16+
public prop() { }
1717
}
1818
class C {
19-
public static name() { }
19+
public static prop() { }
2020
}
2121

2222
var a: A = new B();
23-
a = new C(); // error name is missing
23+
a = new C(); // error prop is missing
2424
~
2525
!!! error TS2322: Type 'C' is not assignable to type 'A'.
26-
!!! error TS2322: Property 'name' is missing in type 'C'.
27-
a = B; // error name is missing
26+
!!! error TS2322: Property 'prop' is missing in type 'C'.
27+
a = B; // error prop is missing
2828
~
2929
!!! error TS2322: Type 'typeof B' is not assignable to type 'A'.
30-
!!! error TS2322: Property 'name' is missing in type 'typeof B'.
30+
!!! error TS2322: Property 'prop' is missing in type 'typeof B'.
3131
a = C;
3232

33-
var b: B = new C(); // error name is missing
33+
var b: B = new C(); // error prop is missing
3434
~
3535
!!! error TS2322: Type 'C' is not assignable to type 'B'.
36-
!!! error TS2322: Property 'name' is missing in type 'C'.
37-
b = B; // error name is missing
36+
!!! error TS2322: Property 'prop' is missing in type 'C'.
37+
b = B; // error prop is missing
3838
~
3939
!!! error TS2322: Type 'typeof B' is not assignable to type 'B'.
40-
!!! error TS2322: Property 'name' is missing in type 'typeof B'.
40+
!!! error TS2322: Property 'prop' is missing in type 'typeof B'.
4141
b = C;
4242
b = a;
4343

tests/baselines/reference/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
//// [staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts]
22
interface A {
3-
name();
3+
prop();
44
}
55
class B {
6-
public name() { }
6+
public prop() { }
77
}
88
class C {
9-
public static name() { }
9+
public static prop() { }
1010
}
1111

1212
var a: A = new B();
13-
a = new C(); // error name is missing
14-
a = B; // error name is missing
13+
a = new C(); // error prop is missing
14+
a = B; // error prop is missing
1515
a = C;
1616

17-
var b: B = new C(); // error name is missing
18-
b = B; // error name is missing
17+
var b: B = new C(); // error prop is missing
18+
b = B; // error prop is missing
1919
b = C;
2020
b = a;
2121

@@ -29,21 +29,21 @@ c = a;
2929
var B = (function () {
3030
function B() {
3131
}
32-
B.prototype.name = function () { };
32+
B.prototype.prop = function () { };
3333
return B;
3434
}());
3535
var C = (function () {
3636
function C() {
3737
}
38-
C.name = function () { };
38+
C.prop = function () { };
3939
return C;
4040
}());
4141
var a = new B();
42-
a = new C(); // error name is missing
43-
a = B; // error name is missing
42+
a = new C(); // error prop is missing
43+
a = B; // error prop is missing
4444
a = C;
45-
var b = new C(); // error name is missing
46-
b = B; // error name is missing
45+
var b = new C(); // error prop is missing
46+
b = B; // error prop is missing
4747
b = C;
4848
b = a;
4949
var c = new B();

0 commit comments

Comments
 (0)