From 5534899e2a0bd6d9e27177d7ab1fd94f06717082 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 24 Aug 2017 14:04:57 -0700 Subject: [PATCH 1/3] Allow string enums in element access Previously literal union types were disallowed to improve errors by printing `boolean` instead of `true | false`. But string enums are literal union types that should be allowed, so now only booleans are disallowed. --- 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 4a07f349c9..08770fc8d8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7688,7 +7688,7 @@ namespace ts { } // In the following we resolve T[K] to the type of the property in T selected by K. const apparentObjectType = getApparentType(objectType); - if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive)) { + if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { const propTypes: Type[] = []; for (const t of (indexType).types) { const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false); From d7d69a16226408aefa78082fcefd7ae5a01ee9f0 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 24 Aug 2017 14:06:21 -0700 Subject: [PATCH 2/3] Test:string enum in element access --- .../reference/stringEnumInElementAccess01.js | 26 +++++++++++ .../stringEnumInElementAccess01.symbols | 40 +++++++++++++++++ .../stringEnumInElementAccess01.types | 44 +++++++++++++++++++ .../stringEnumInElementAccess01.ts | 16 +++++++ 4 files changed, 126 insertions(+) create mode 100644 tests/baselines/reference/stringEnumInElementAccess01.js create mode 100644 tests/baselines/reference/stringEnumInElementAccess01.symbols create mode 100644 tests/baselines/reference/stringEnumInElementAccess01.types create mode 100644 tests/cases/conformance/expressions/elementAccess/stringEnumInElementAccess01.ts diff --git a/tests/baselines/reference/stringEnumInElementAccess01.js b/tests/baselines/reference/stringEnumInElementAccess01.js new file mode 100644 index 0000000000..6dadb919a3 --- /dev/null +++ b/tests/baselines/reference/stringEnumInElementAccess01.js @@ -0,0 +1,26 @@ +//// [stringEnumInElementAccess01.ts] +enum E { + A = "a", + B = "b", + C = "c", +} + +interface Item { + a: string; + b: number; + c: boolean; +} + +declare const item: Item; +declare const e: E; +const snb: string | number | boolean = item[e]; + + +//// [stringEnumInElementAccess01.js] +var E; +(function (E) { + E["A"] = "a"; + E["B"] = "b"; + E["C"] = "c"; +})(E || (E = {})); +var snb = item[e]; diff --git a/tests/baselines/reference/stringEnumInElementAccess01.symbols b/tests/baselines/reference/stringEnumInElementAccess01.symbols new file mode 100644 index 0000000000..337edf1d59 --- /dev/null +++ b/tests/baselines/reference/stringEnumInElementAccess01.symbols @@ -0,0 +1,40 @@ +=== tests/cases/conformance/expressions/elementAccess/stringEnumInElementAccess01.ts === +enum E { +>E : Symbol(E, Decl(stringEnumInElementAccess01.ts, 0, 0)) + + A = "a", +>A : Symbol(E.A, Decl(stringEnumInElementAccess01.ts, 0, 8)) + + B = "b", +>B : Symbol(E.B, Decl(stringEnumInElementAccess01.ts, 1, 12)) + + C = "c", +>C : Symbol(E.C, Decl(stringEnumInElementAccess01.ts, 2, 12)) +} + +interface Item { +>Item : Symbol(Item, Decl(stringEnumInElementAccess01.ts, 4, 1)) + + a: string; +>a : Symbol(Item.a, Decl(stringEnumInElementAccess01.ts, 6, 16)) + + b: number; +>b : Symbol(Item.b, Decl(stringEnumInElementAccess01.ts, 7, 14)) + + c: boolean; +>c : Symbol(Item.c, Decl(stringEnumInElementAccess01.ts, 8, 14)) +} + +declare const item: Item; +>item : Symbol(item, Decl(stringEnumInElementAccess01.ts, 12, 13)) +>Item : Symbol(Item, Decl(stringEnumInElementAccess01.ts, 4, 1)) + +declare const e: E; +>e : Symbol(e, Decl(stringEnumInElementAccess01.ts, 13, 13)) +>E : Symbol(E, Decl(stringEnumInElementAccess01.ts, 0, 0)) + +const snb: string | number | boolean = item[e]; +>snb : Symbol(snb, Decl(stringEnumInElementAccess01.ts, 14, 5)) +>item : Symbol(item, Decl(stringEnumInElementAccess01.ts, 12, 13)) +>e : Symbol(e, Decl(stringEnumInElementAccess01.ts, 13, 13)) + diff --git a/tests/baselines/reference/stringEnumInElementAccess01.types b/tests/baselines/reference/stringEnumInElementAccess01.types new file mode 100644 index 0000000000..f0e878f776 --- /dev/null +++ b/tests/baselines/reference/stringEnumInElementAccess01.types @@ -0,0 +1,44 @@ +=== tests/cases/conformance/expressions/elementAccess/stringEnumInElementAccess01.ts === +enum E { +>E : E + + A = "a", +>A : E.A +>"a" : "a" + + B = "b", +>B : E.B +>"b" : "b" + + C = "c", +>C : E.C +>"c" : "c" +} + +interface Item { +>Item : Item + + a: string; +>a : string + + b: number; +>b : number + + c: boolean; +>c : boolean +} + +declare const item: Item; +>item : Item +>Item : Item + +declare const e: E; +>e : E +>E : E + +const snb: string | number | boolean = item[e]; +>snb : string | number | boolean +>item[e] : string | number | boolean +>item : Item +>e : E + diff --git a/tests/cases/conformance/expressions/elementAccess/stringEnumInElementAccess01.ts b/tests/cases/conformance/expressions/elementAccess/stringEnumInElementAccess01.ts new file mode 100644 index 0000000000..2dc07cb0e4 --- /dev/null +++ b/tests/cases/conformance/expressions/elementAccess/stringEnumInElementAccess01.ts @@ -0,0 +1,16 @@ +// @noImplicitAny: true +enum E { + A = "a", + B = "b", + C = "c", +} + +interface Item { + a: string; + b: number; + c: boolean; +} + +declare const item: Item; +declare const e: E; +const snb: string | number | boolean = item[e]; From 8087206078f07f99f4e70f257661575e505ac293 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 28 Aug 2017 11:09:25 -0700 Subject: [PATCH 3/3] Explain boolean exception in getIndexedAccessType Booleans are not treated like other unions in order to skip straight to error reporting so that the error is reported with 'boolean' instead of 'true'. --- src/compiler/checker.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8acecf57e5..69862a93d2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7693,6 +7693,8 @@ namespace ts { return type; } // In the following we resolve T[K] to the type of the property in T selected by K. + // We treat boolean as different from other unions to improve errors; + // skipping straight to getPropertyTypeForIndexType gives errors with 'boolean' instead of 'true'. const apparentObjectType = getApparentType(objectType); if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { const propTypes: Type[] = [];