Skip to content

Commit a4faad5

Browse files
committed
Add static index
1 parent 78a9924 commit a4faad5

21 files changed

+343
-54
lines changed

src/compiler/checker.ts

+41-17
Original file line numberDiff line numberDiff line change
@@ -8580,8 +8580,8 @@ namespace ts {
85808580
if (merged) {
85818581
// note:we overwrite links because we just cloned the symbol
85828582
symbol = links = merged;
8583-
}
8584-
8583+
}
8584+
85858585
const type = originalLinks.declaredType = links.declaredType = <InterfaceType>createObjectType(kind, symbol);
85868586
const outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol);
85878587
const localTypeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
@@ -9611,6 +9611,7 @@ namespace ts {
96119611
// Combinations of function, class, enum and module
96129612
let members = emptySymbols;
96139613
let stringIndexInfo: IndexInfo | undefined;
9614+
let numberIndexInfo: IndexInfo | undefined;
96149615
if (symbol.exports) {
96159616
members = getExportsOfSymbol(symbol);
96169617
if (symbol === globalThisSymbol) {
@@ -9623,6 +9624,7 @@ namespace ts {
96239624
members = varsOnly;
96249625
}
96259626
}
9627+
let baseConstructorIndexInfo: IndexInfo | undefined;
96269628
setStructuredTypeMembers(type, members, emptyArray, emptyArray, undefined, undefined);
96279629
if (symbol.flags & SymbolFlags.Class) {
96289630
const classType = getDeclaredTypeOfClassOrInterface(symbol);
@@ -9632,11 +9634,21 @@ namespace ts {
96329634
addInheritedMembers(members, getPropertiesOfType(baseConstructorType));
96339635
}
96349636
else if (baseConstructorType === anyType) {
9635-
stringIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
9637+
baseConstructorIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
9638+
}
9639+
}
9640+
9641+
const indexSymbol = getIndexSymbolFromSymbolTable(members);
9642+
if (indexSymbol) {
9643+
stringIndexInfo = getIndexInfoOfIndexSymbol(indexSymbol, IndexKind.String);
9644+
numberIndexInfo = getIndexInfoOfIndexSymbol(indexSymbol, IndexKind.Number);
9645+
}
9646+
else {
9647+
stringIndexInfo = baseConstructorIndexInfo;
9648+
if (symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) ) {
9649+
numberIndexInfo = enumNumberIndexInfo;
96369650
}
96379651
}
9638-
const numberIndexInfo = symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum ||
9639-
some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) ? enumNumberIndexInfo : undefined;
96409652
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
96419653
// We resolve the members before computing the signatures because a signature may use
96429654
// typeof with a qualified name expression that circularly references the type we are
@@ -9664,6 +9676,13 @@ namespace ts {
96649676
}
96659677
}
96669678

9679+
function getIndexInfoOfIndexSymbol(indexSymbol: Symbol, indexKind: IndexKind) {
9680+
const declaration = getIndexDeclarationOfIndexSymbol(indexSymbol, indexKind);
9681+
if (!declaration) return undefined;
9682+
return createIndexInfo(declaration.type ? getTypeFromTypeNode(declaration.type) : anyType,
9683+
hasModifier(declaration, ModifierFlags.Readonly), declaration);
9684+
}
9685+
96679686
function resolveReverseMappedTypeMembers(type: ReverseMappedType) {
96689687
const indexInfo = getIndexInfoOfType(type.source, IndexKind.String);
96699688
const modifiers = getMappedTypeModifiers(type.mappedType);
@@ -11094,24 +11113,29 @@ namespace ts {
1109411113
}
1109511114

1109611115
function getIndexSymbol(symbol: Symbol): Symbol | undefined {
11097-
return symbol.members!.get(InternalSymbolName.Index);
11116+
return getIndexSymbolFromSymbolTable(symbol.members!);
11117+
}
11118+
11119+
function getIndexSymbolFromSymbolTable(symbolTable: SymbolTable): Symbol | undefined {
11120+
return symbolTable.get(InternalSymbolName.Index);
1109811121
}
1109911122

1110011123
function getIndexDeclarationOfSymbol(symbol: Symbol, kind: IndexKind): IndexSignatureDeclaration | undefined {
11101-
const syntaxKind = kind === IndexKind.Number ? SyntaxKind.NumberKeyword : SyntaxKind.StringKeyword;
1110211124
const indexSymbol = getIndexSymbol(symbol);
11103-
if (indexSymbol) {
11104-
for (const decl of indexSymbol.declarations) {
11105-
const node = cast(decl, isIndexSignatureDeclaration);
11106-
if (node.parameters.length === 1) {
11107-
const parameter = node.parameters[0];
11108-
if (parameter.type && parameter.type.kind === syntaxKind) {
11109-
return node;
11110-
}
11125+
return indexSymbol && getIndexDeclarationOfIndexSymbol(indexSymbol, kind);
11126+
}
11127+
11128+
function getIndexDeclarationOfIndexSymbol(indexSymbol: Symbol, kind: IndexKind): IndexSignatureDeclaration | undefined {
11129+
const syntaxKind = kind === IndexKind.Number ? SyntaxKind.NumberKeyword : SyntaxKind.StringKeyword;
11130+
for (const decl of indexSymbol.declarations) {
11131+
const node = cast(decl, isIndexSignatureDeclaration);
11132+
if (node.parameters.length === 1) {
11133+
const parameter = node.parameters[0];
11134+
if (parameter.type && parameter.type.kind === syntaxKind) {
11135+
return node;
1111111136
}
1111211137
}
1111311138
}
11114-
1111511139
return undefined;
1111611140
}
1111711141

@@ -36337,7 +36361,7 @@ namespace ts {
3633736361
if (node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.MethodSignature) {
3633836362
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_member, tokenToString(modifier.kind));
3633936363
}
36340-
if (node.kind === SyntaxKind.IndexSignature) {
36364+
if (node.kind === SyntaxKind.IndexSignature && modifier.kind !== SyntaxKind.StaticKeyword) {
3634136365
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind));
3634236366
}
3634336367
}

src/compiler/parser.ts

+5
Original file line numberDiff line numberDiff line change
@@ -2824,6 +2824,10 @@ namespace ts {
28242824
}
28252825

28262826
function isIndexSignature(): boolean {
2827+
return token() === SyntaxKind.StaticKeyword ? lookAhead(isNonStaticIndexSignature) : isNonStaticIndexSignature()
2828+
}
2829+
2830+
function isNonStaticIndexSignature(): boolean {
28272831
return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature);
28282832
}
28292833

@@ -2884,6 +2888,7 @@ namespace ts {
28842888

28852889
function parseIndexSignatureDeclaration(node: IndexSignatureDeclaration): IndexSignatureDeclaration {
28862890
node.kind = SyntaxKind.IndexSignature;
2891+
node.staticModifier = parseOptionalToken(SyntaxKind.StaticKeyword);
28872892
node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
28882893
node.type = parseTypeAnnotation();
28892894
parseTypeMemberSemicolon();

src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,7 @@ namespace ts {
11841184
export interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement {
11851185
kind: SyntaxKind.IndexSignature;
11861186
parent: ObjectTypeDeclaration;
1187+
staticModifier?: Token<SyntaxKind.StaticKeyword>;
11871188
}
11881189

11891190
export interface TypeNode extends Node {

tests/baselines/reference/api/tsserverlibrary.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ declare namespace ts {
752752
export interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement {
753753
kind: SyntaxKind.IndexSignature;
754754
parent: ObjectTypeDeclaration;
755+
staticModifier?: Token<SyntaxKind.StaticKeyword>;
755756
}
756757
export interface TypeNode extends Node {
757758
_typeNodeBrand: any;

tests/baselines/reference/api/typescript.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ declare namespace ts {
752752
export interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement {
753753
kind: SyntaxKind.IndexSignature;
754754
parent: ObjectTypeDeclaration;
755+
staticModifier?: Token<SyntaxKind.StaticKeyword>;
755756
}
756757
export interface TypeNode extends Node {
757758
_typeNodeBrand: any;
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
tests/cases/conformance/parser/ecmascript5/IndexMemberDeclarations/parserIndexMemberDeclaration10.ts(2,4): error TS1071: 'static' modifier cannot appear on an index signature.
1+
tests/cases/conformance/parser/ecmascript5/IndexMemberDeclarations/parserIndexMemberDeclaration10.ts(2,11): error TS1030: 'static' modifier already seen.
22

33

44
==== tests/cases/conformance/parser/ecmascript5/IndexMemberDeclarations/parserIndexMemberDeclaration10.ts (1 errors) ====
55
class C {
66
static static [x: string]: string;
7-
~~~~~~
8-
!!! error TS1071: 'static' modifier cannot appear on an index signature.
7+
~~~~~~
8+
!!! error TS1030: 'static' modifier already seen.
99
}

tests/baselines/reference/parserIndexMemberDeclaration6.errors.txt

-9
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
tests/cases/conformance/parser/ecmascript6/Symbols/parserSymbolIndexer3.ts(2,5): error TS1071: 'static' modifier cannot appear on an index signature.
1+
tests/cases/conformance/parser/ecmascript6/Symbols/parserSymbolIndexer3.ts(2,13): error TS1023: An index signature parameter type must be either 'string' or 'number'.
22

33

44
==== tests/cases/conformance/parser/ecmascript6/Symbols/parserSymbolIndexer3.ts (1 errors) ====
55
class C {
66
static [s: symbol]: string;
7-
~~~~~~
8-
!!! error TS1071: 'static' modifier cannot appear on an index signature.
7+
~
8+
!!! error TS1023: An index signature parameter type must be either 'string' or 'number'.
99
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
tests/cases/compiler/staticAsIdentifier.ts(2,5): error TS1071: 'static' modifier cannot appear on an index signature.
1+
tests/cases/compiler/staticAsIdentifier.ts(2,12): error TS1030: 'static' modifier already seen.
22

33

44
==== tests/cases/compiler/staticAsIdentifier.ts (1 errors) ====
55
class C {
66
static static
7-
~~~~~~
8-
!!! error TS1071: 'static' modifier cannot appear on an index signature.
7+
~~~~~~
8+
!!! error TS1030: 'static' modifier already seen.
99
[x: string]: string;
1010
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/staticIndexSignature1.ts(10,1): error TS2322: Type '2' is not assignable to type '42'.
2+
3+
4+
==== tests/cases/compiler/staticIndexSignature1.ts (1 errors) ====
5+
class C {
6+
static [s: string]: number;
7+
static [s: number]: 42
8+
}
9+
10+
C["foo"] = 1
11+
C.bar = 2;
12+
const foo = C["foo"]
13+
C[42] = 42
14+
C[2] = 2;
15+
~~~~
16+
!!! error TS2322: Type '2' is not assignable to type '42'.
17+
const bar = C[42]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [staticIndexSignature1.ts]
2+
class C {
3+
static [s: string]: number;
4+
static [s: number]: 42
5+
}
6+
7+
C["foo"] = 1
8+
C.bar = 2;
9+
const foo = C["foo"]
10+
C[42] = 42
11+
C[2] = 2;
12+
const bar = C[42]
13+
14+
//// [staticIndexSignature1.js]
15+
var C = /** @class */ (function () {
16+
function C() {
17+
}
18+
return C;
19+
}());
20+
C["foo"] = 1;
21+
C.bar = 2;
22+
var foo = C["foo"];
23+
C[42] = 42;
24+
C[2] = 2;
25+
var bar = C[42];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/compiler/staticIndexSignature1.ts ===
2+
class C {
3+
>C : Symbol(C, Decl(staticIndexSignature1.ts, 0, 0))
4+
5+
static [s: string]: number;
6+
>s : Symbol(s, Decl(staticIndexSignature1.ts, 1, 12))
7+
8+
static [s: number]: 42
9+
>s : Symbol(s, Decl(staticIndexSignature1.ts, 2, 12))
10+
}
11+
12+
C["foo"] = 1
13+
>C : Symbol(C, Decl(staticIndexSignature1.ts, 0, 0))
14+
15+
C.bar = 2;
16+
>C : Symbol(C, Decl(staticIndexSignature1.ts, 0, 0))
17+
18+
const foo = C["foo"]
19+
>foo : Symbol(foo, Decl(staticIndexSignature1.ts, 7, 5))
20+
>C : Symbol(C, Decl(staticIndexSignature1.ts, 0, 0))
21+
22+
C[42] = 42
23+
>C : Symbol(C, Decl(staticIndexSignature1.ts, 0, 0))
24+
25+
C[2] = 2;
26+
>C : Symbol(C, Decl(staticIndexSignature1.ts, 0, 0))
27+
28+
const bar = C[42]
29+
>bar : Symbol(bar, Decl(staticIndexSignature1.ts, 10, 5))
30+
>C : Symbol(C, Decl(staticIndexSignature1.ts, 0, 0))
31+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
=== tests/cases/compiler/staticIndexSignature1.ts ===
2+
class C {
3+
>C : C
4+
5+
static [s: string]: number;
6+
>s : string
7+
8+
static [s: number]: 42
9+
>s : number
10+
}
11+
12+
C["foo"] = 1
13+
>C["foo"] = 1 : 1
14+
>C["foo"] : number
15+
>C : typeof C
16+
>"foo" : "foo"
17+
>1 : 1
18+
19+
C.bar = 2;
20+
>C.bar = 2 : 2
21+
>C.bar : number
22+
>C : typeof C
23+
>bar : number
24+
>2 : 2
25+
26+
const foo = C["foo"]
27+
>foo : number
28+
>C["foo"] : number
29+
>C : typeof C
30+
>"foo" : "foo"
31+
32+
C[42] = 42
33+
>C[42] = 42 : 42
34+
>C[42] : 42
35+
>C : typeof C
36+
>42 : 42
37+
>42 : 42
38+
39+
C[2] = 2;
40+
>C[2] = 2 : 2
41+
>C[2] : 42
42+
>C : typeof C
43+
>2 : 2
44+
>2 : 2
45+
46+
const bar = C[42]
47+
>bar : 42
48+
>C[42] : 42
49+
>C : typeof C
50+
>42 : 42
51+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
tests/cases/compiler/staticIndexSignature2.ts(6,1): error TS2542: Index signature in type 'typeof C' only permits reading.
2+
tests/cases/compiler/staticIndexSignature2.ts(7,1): error TS2542: Index signature in type 'typeof C' only permits reading.
3+
tests/cases/compiler/staticIndexSignature2.ts(9,1): error TS2542: Index signature in type 'typeof C' only permits reading.
4+
tests/cases/compiler/staticIndexSignature2.ts(10,1): error TS2322: Type '2' is not assignable to type '42'.
5+
tests/cases/compiler/staticIndexSignature2.ts(10,1): error TS2542: Index signature in type 'typeof C' only permits reading.
6+
7+
8+
==== tests/cases/compiler/staticIndexSignature2.ts (5 errors) ====
9+
class C {
10+
static readonly [s: string]: number;
11+
static readonly [s: number]: 42
12+
}
13+
14+
C["foo"] = 1
15+
~~~~~~~~
16+
!!! error TS2542: Index signature in type 'typeof C' only permits reading.
17+
C.bar = 2;
18+
~~~~~
19+
!!! error TS2542: Index signature in type 'typeof C' only permits reading.
20+
const foo = C["foo"]
21+
C[42] = 42
22+
~~~~~
23+
!!! error TS2542: Index signature in type 'typeof C' only permits reading.
24+
C[2] = 2;
25+
~~~~
26+
!!! error TS2322: Type '2' is not assignable to type '42'.
27+
~~~~
28+
!!! error TS2542: Index signature in type 'typeof C' only permits reading.
29+
const bar = C[42]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [staticIndexSignature2.ts]
2+
class C {
3+
static readonly [s: string]: number;
4+
static readonly [s: number]: 42
5+
}
6+
7+
C["foo"] = 1
8+
C.bar = 2;
9+
const foo = C["foo"]
10+
C[42] = 42
11+
C[2] = 2;
12+
const bar = C[42]
13+
14+
//// [staticIndexSignature2.js]
15+
var C = /** @class */ (function () {
16+
function C() {
17+
}
18+
return C;
19+
}());
20+
C["foo"] = 1;
21+
C.bar = 2;
22+
var foo = C["foo"];
23+
C[42] = 42;
24+
C[2] = 2;
25+
var bar = C[42];

0 commit comments

Comments
 (0)