From b688e25cd37b4e0df5727846a02295e8b84ca702 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 22 May 2019 17:12:37 -0700 Subject: [PATCH 1/5] Implement inferrable index signatures for enum types --- src/compiler/checker.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9e5c864f6b975..e786eca9981d1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7299,7 +7299,8 @@ namespace ts { stringIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false); } } - const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined; + const numberIndexInfo = symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || + some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) ? enumNumberIndexInfo : undefined; setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); // We resolve the members before computing the signatures because a signature may use // typeof with a qualified name expression that circularly references the type we are @@ -8161,6 +8162,9 @@ namespace ts { propTypes.push(getTypeOfSymbol(prop)); } } + if (kind === IndexKind.String) { + append(propTypes, getIndexTypeOfType(type, IndexKind.Number)); + } if (propTypes.length) { return getUnionType(propTypes, UnionReduction.Subtype); } @@ -14498,7 +14502,7 @@ namespace ts { * with no call or construct signatures. */ function isObjectTypeWithInferableIndex(type: Type) { - return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.ValueModule)) !== 0 && + return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum| SymbolFlags.ValueModule)) !== 0 && !typeHasCallOrConstructSignatures(type); } From a95d18e7b4492e0cba86e295b767a9516167646b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 22 May 2019 17:13:36 -0700 Subject: [PATCH 2/5] Accept new baselines --- .../baselines/reference/useObjectValuesAndEntries1.types | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/useObjectValuesAndEntries1.types b/tests/baselines/reference/useObjectValuesAndEntries1.types index 94deebdfd8caa..bbfd4c87d2a92 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries1.types +++ b/tests/baselines/reference/useObjectValuesAndEntries1.types @@ -121,16 +121,16 @@ enum E { A, B } >B : E.B var entries5 = Object.entries(E); // [string, any][] ->entries5 : [string, any][] ->Object.entries(E) : [string, any][] +>entries5 : [string, string | E][] +>Object.entries(E) : [string, string | E][] >Object.entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } >Object : ObjectConstructor >entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } >E : typeof E var values5 = Object.values(E); // any[] ->values5 : any[] ->Object.values(E) : any[] +>values5 : (string | E)[] +>Object.values(E) : (string | E)[] >Object.values : { (o: { [s: string]: T; } | ArrayLike): T[]; (o: {}): any[]; } >Object : ObjectConstructor >values : { (o: { [s: string]: T; } | ArrayLike): T[]; (o: {}): any[]; } From cf1bceb9e4a90b2425ff46fee3a9b01c7fbb7c60 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 30 May 2019 17:35:10 -0700 Subject: [PATCH 3/5] Add tests --- tests/cases/compiler/implicitIndexSignatures.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/cases/compiler/implicitIndexSignatures.ts b/tests/cases/compiler/implicitIndexSignatures.ts index 2e36a91badab3..2239ad8a8e224 100644 --- a/tests/cases/compiler/implicitIndexSignatures.ts +++ b/tests/cases/compiler/implicitIndexSignatures.ts @@ -43,3 +43,15 @@ function f4() { const v3 = getNumberIndexValue(o1); const v4 = getNumberIndexValue(o2); } + +function f5() { + enum E1 { A, B } + enum E2 { A = "A", B = "B" } + enum E3 { A = 0, B = "B" } + const v1 = getStringIndexValue(E1); + const v2 = getStringIndexValue(E2); + const v3 = getStringIndexValue(E3); + const v4 = getNumberIndexValue(E1); + const v5 = getNumberIndexValue(E2); + const v6 = getNumberIndexValue(E3); +} From 8bd6fd85db1b4952b7d43c7efadbc0f6278ad5ec Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 30 May 2019 17:35:17 -0700 Subject: [PATCH 4/5] Accept new baselines --- .../reference/implicitIndexSignatures.js | 35 +++++++++++ .../reference/implicitIndexSignatures.symbols | 49 +++++++++++++++ .../reference/implicitIndexSignatures.types | 59 +++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/tests/baselines/reference/implicitIndexSignatures.js b/tests/baselines/reference/implicitIndexSignatures.js index 6403f1f154345..a20c63979da4e 100644 --- a/tests/baselines/reference/implicitIndexSignatures.js +++ b/tests/baselines/reference/implicitIndexSignatures.js @@ -44,6 +44,18 @@ function f4() { const v3 = getNumberIndexValue(o1); const v4 = getNumberIndexValue(o2); } + +function f5() { + enum E1 { A, B } + enum E2 { A = "A", B = "B" } + enum E3 { A = 0, B = "B" } + const v1 = getStringIndexValue(E1); + const v2 = getStringIndexValue(E2); + const v3 = getStringIndexValue(E3); + const v4 = getNumberIndexValue(E1); + const v5 = getNumberIndexValue(E2); + const v6 = getNumberIndexValue(E3); +} //// [implicitIndexSignatures.js] @@ -83,3 +95,26 @@ function f4() { var v3 = getNumberIndexValue(o1); var v4 = getNumberIndexValue(o2); } +function f5() { + var E1; + (function (E1) { + E1[E1["A"] = 0] = "A"; + E1[E1["B"] = 1] = "B"; + })(E1 || (E1 = {})); + var E2; + (function (E2) { + E2["A"] = "A"; + E2["B"] = "B"; + })(E2 || (E2 = {})); + var E3; + (function (E3) { + E3[E3["A"] = 0] = "A"; + E3["B"] = "B"; + })(E3 || (E3 = {})); + var v1 = getStringIndexValue(E1); + var v2 = getStringIndexValue(E2); + var v3 = getStringIndexValue(E3); + var v4 = getNumberIndexValue(E1); + var v5 = getNumberIndexValue(E2); + var v6 = getNumberIndexValue(E3); +} diff --git a/tests/baselines/reference/implicitIndexSignatures.symbols b/tests/baselines/reference/implicitIndexSignatures.symbols index 1c8f06acc11ed..6f3e68f5058c6 100644 --- a/tests/baselines/reference/implicitIndexSignatures.symbols +++ b/tests/baselines/reference/implicitIndexSignatures.symbols @@ -168,3 +168,52 @@ function f4() { >o2 : Symbol(o2, Decl(implicitIndexSignatures.ts, 39, 7)) } +function f5() { +>f5 : Symbol(f5, Decl(implicitIndexSignatures.ts, 44, 1)) + + enum E1 { A, B } +>E1 : Symbol(E1, Decl(implicitIndexSignatures.ts, 46, 15)) +>A : Symbol(E1.A, Decl(implicitIndexSignatures.ts, 47, 13)) +>B : Symbol(E1.B, Decl(implicitIndexSignatures.ts, 47, 16)) + + enum E2 { A = "A", B = "B" } +>E2 : Symbol(E2, Decl(implicitIndexSignatures.ts, 47, 20)) +>A : Symbol(E2.A, Decl(implicitIndexSignatures.ts, 48, 13)) +>B : Symbol(E2.B, Decl(implicitIndexSignatures.ts, 48, 22)) + + enum E3 { A = 0, B = "B" } +>E3 : Symbol(E3, Decl(implicitIndexSignatures.ts, 48, 32)) +>A : Symbol(E3.A, Decl(implicitIndexSignatures.ts, 49, 13)) +>B : Symbol(E3.B, Decl(implicitIndexSignatures.ts, 49, 20)) + + const v1 = getStringIndexValue(E1); +>v1 : Symbol(v1, Decl(implicitIndexSignatures.ts, 50, 9)) +>getStringIndexValue : Symbol(getStringIndexValue, Decl(implicitIndexSignatures.ts, 11, 13)) +>E1 : Symbol(E1, Decl(implicitIndexSignatures.ts, 46, 15)) + + const v2 = getStringIndexValue(E2); +>v2 : Symbol(v2, Decl(implicitIndexSignatures.ts, 51, 9)) +>getStringIndexValue : Symbol(getStringIndexValue, Decl(implicitIndexSignatures.ts, 11, 13)) +>E2 : Symbol(E2, Decl(implicitIndexSignatures.ts, 47, 20)) + + const v3 = getStringIndexValue(E3); +>v3 : Symbol(v3, Decl(implicitIndexSignatures.ts, 52, 9)) +>getStringIndexValue : Symbol(getStringIndexValue, Decl(implicitIndexSignatures.ts, 11, 13)) +>E3 : Symbol(E3, Decl(implicitIndexSignatures.ts, 48, 32)) + + const v4 = getNumberIndexValue(E1); +>v4 : Symbol(v4, Decl(implicitIndexSignatures.ts, 53, 9)) +>getNumberIndexValue : Symbol(getNumberIndexValue, Decl(implicitIndexSignatures.ts, 13, 68)) +>E1 : Symbol(E1, Decl(implicitIndexSignatures.ts, 46, 15)) + + const v5 = getNumberIndexValue(E2); +>v5 : Symbol(v5, Decl(implicitIndexSignatures.ts, 54, 9)) +>getNumberIndexValue : Symbol(getNumberIndexValue, Decl(implicitIndexSignatures.ts, 13, 68)) +>E2 : Symbol(E2, Decl(implicitIndexSignatures.ts, 47, 20)) + + const v6 = getNumberIndexValue(E3); +>v6 : Symbol(v6, Decl(implicitIndexSignatures.ts, 55, 9)) +>getNumberIndexValue : Symbol(getNumberIndexValue, Decl(implicitIndexSignatures.ts, 13, 68)) +>E3 : Symbol(E3, Decl(implicitIndexSignatures.ts, 48, 32)) +} + diff --git a/tests/baselines/reference/implicitIndexSignatures.types b/tests/baselines/reference/implicitIndexSignatures.types index afad7bed570b1..c302edba32fd2 100644 --- a/tests/baselines/reference/implicitIndexSignatures.types +++ b/tests/baselines/reference/implicitIndexSignatures.types @@ -196,3 +196,62 @@ function f4() { >o2 : { 0: string; 1: string; count: number; } } +function f5() { +>f5 : () => void + + enum E1 { A, B } +>E1 : E1 +>A : E1.A +>B : E1.B + + enum E2 { A = "A", B = "B" } +>E2 : E2 +>A : E2.A +>"A" : "A" +>B : E2.B +>"B" : "B" + + enum E3 { A = 0, B = "B" } +>E3 : E3 +>A : E3.A +>0 : 0 +>B : E3.B +>"B" : "B" + + const v1 = getStringIndexValue(E1); +>v1 : string | E1 +>getStringIndexValue(E1) : string | E1 +>getStringIndexValue : (map: { [x: string]: T; }) => T +>E1 : typeof E1 + + const v2 = getStringIndexValue(E2); +>v2 : E2 +>getStringIndexValue(E2) : E2 +>getStringIndexValue : (map: { [x: string]: T; }) => T +>E2 : typeof E2 + + const v3 = getStringIndexValue(E3); +>v3 : string | E3.A +>getStringIndexValue(E3) : string | E3.A +>getStringIndexValue : (map: { [x: string]: T; }) => T +>E3 : typeof E3 + + const v4 = getNumberIndexValue(E1); +>v4 : string +>getNumberIndexValue(E1) : string +>getNumberIndexValue : (map: { [x: number]: T; }) => T +>E1 : typeof E1 + + const v5 = getNumberIndexValue(E2); +>v5 : unknown +>getNumberIndexValue(E2) : unknown +>getNumberIndexValue : (map: { [x: number]: T; }) => T +>E2 : typeof E2 + + const v6 = getNumberIndexValue(E3); +>v6 : string +>getNumberIndexValue(E3) : string +>getNumberIndexValue : (map: { [x: number]: T; }) => T +>E3 : typeof E3 +} + From bb15df3e435e14a85b4a6dc15c000f7eb6af50af Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 30 May 2019 21:06:51 -0700 Subject: [PATCH 5/5] Fix lint error --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0fdb88110ebf9..8342dbc229179 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14600,7 +14600,7 @@ namespace ts { * with no call or construct signatures. */ function isObjectTypeWithInferableIndex(type: Type) { - return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum| SymbolFlags.ValueModule)) !== 0 && + return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 && !typeHasCallOrConstructSignatures(type); }