diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a3808fd56e21a..20d075cdfc07f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23665,7 +23665,7 @@ namespace ts { } if (isEntityNameExpression(node.argumentExpression)) { const symbol = resolveEntityName(node.argumentExpression, SymbolFlags.Value, /*ignoreErrors*/ true); - if (!symbol || !isConstVariable(symbol)) return undefined; + if (!symbol || !(isConstVariable(symbol) || (symbol.flags & SymbolFlags.EnumMember))) return undefined; const declaration = symbol.valueDeclaration; if (declaration === undefined) return undefined; @@ -23680,7 +23680,12 @@ namespace ts { if (hasOnlyExpressionInitializer(declaration) && isBlockScopedNameDeclaredBeforeUse(declaration, node.argumentExpression)) { const initializer = getEffectiveInitializer(declaration); - return initializer && tryGetNameFromType(getTypeOfExpression(initializer)); + if (initializer) { + return tryGetNameFromType(getTypeOfExpression(initializer)); + } + if (isEnumMember(declaration)) { + return getTextOfPropertyName(declaration.name); + } } } return undefined; diff --git a/tests/baselines/reference/strictPropertyInitialization.errors.txt b/tests/baselines/reference/strictPropertyInitialization.errors.txt index 208c0a32e4d1d..7e3a834b84f40 100644 --- a/tests/baselines/reference/strictPropertyInitialization.errors.txt +++ b/tests/baselines/reference/strictPropertyInitialization.errors.txt @@ -179,4 +179,15 @@ tests/cases/conformance/classes/propertyMemberDeclarations/strictPropertyInitial this['c'] = 1; } } + + enum E { + A = "A", + B = "B" + } + class C13 { + [E.A]: number; + constructor() { + this[E.A] = 1; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/strictPropertyInitialization.js b/tests/baselines/reference/strictPropertyInitialization.js index 41760958edd1f..43411f15ad837 100644 --- a/tests/baselines/reference/strictPropertyInitialization.js +++ b/tests/baselines/reference/strictPropertyInitialization.js @@ -147,6 +147,17 @@ class C12 { this['c'] = 1; } } + +enum E { + A = "A", + B = "B" +} +class C13 { + [E.A]: number; + constructor() { + this[E.A] = 1; + } +} //// [strictPropertyInitialization.js] @@ -259,6 +270,17 @@ class C12 { this['c'] = 1; } } +var E; +(function (E) { + E["A"] = "A"; + E["B"] = "B"; +})(E || (E = {})); +class C13 { + constructor() { + this[E.A] = 1; + } +} +E.A; //// [strictPropertyInitialization.d.ts] @@ -335,3 +357,11 @@ declare class C12 { ['c']: number; constructor(); } +declare enum E { + A = "A", + B = "B" +} +declare class C13 { + [E.A]: number; + constructor(); +} diff --git a/tests/baselines/reference/strictPropertyInitialization.symbols b/tests/baselines/reference/strictPropertyInitialization.symbols index 45e15f21403e5..3b81ef3d31835 100644 --- a/tests/baselines/reference/strictPropertyInitialization.symbols +++ b/tests/baselines/reference/strictPropertyInitialization.symbols @@ -348,3 +348,30 @@ class C12 { } } +enum E { +>E : Symbol(E, Decl(strictPropertyInitialization.ts, 147, 1)) + + A = "A", +>A : Symbol(E.A, Decl(strictPropertyInitialization.ts, 149, 8)) + + B = "B" +>B : Symbol(E.B, Decl(strictPropertyInitialization.ts, 150, 12)) +} +class C13 { +>C13 : Symbol(C13, Decl(strictPropertyInitialization.ts, 152, 1)) + + [E.A]: number; +>[E.A] : Symbol(C13[E.A], Decl(strictPropertyInitialization.ts, 153, 11)) +>E.A : Symbol(E.A, Decl(strictPropertyInitialization.ts, 149, 8)) +>E : Symbol(E, Decl(strictPropertyInitialization.ts, 147, 1)) +>A : Symbol(E.A, Decl(strictPropertyInitialization.ts, 149, 8)) + + constructor() { + this[E.A] = 1; +>this : Symbol(C13, Decl(strictPropertyInitialization.ts, 152, 1)) +>E.A : Symbol(E.A, Decl(strictPropertyInitialization.ts, 149, 8)) +>E : Symbol(E, Decl(strictPropertyInitialization.ts, 147, 1)) +>A : Symbol(E.A, Decl(strictPropertyInitialization.ts, 149, 8)) + } +} + diff --git a/tests/baselines/reference/strictPropertyInitialization.types b/tests/baselines/reference/strictPropertyInitialization.types index 84d375c85157a..616e41d9be324 100644 --- a/tests/baselines/reference/strictPropertyInitialization.types +++ b/tests/baselines/reference/strictPropertyInitialization.types @@ -395,3 +395,35 @@ class C12 { } } +enum E { +>E : E + + A = "A", +>A : E.A +>"A" : "A" + + B = "B" +>B : E.B +>"B" : "B" +} +class C13 { +>C13 : C13 + + [E.A]: number; +>[E.A] : number +>E.A : E.A +>E : typeof E +>A : E.A + + constructor() { + this[E.A] = 1; +>this[E.A] = 1 : 1 +>this[E.A] : number +>this : this +>E.A : E.A +>E : typeof E +>A : E.A +>1 : 1 + } +} + diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.js b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.js new file mode 100644 index 0000000000000..64d1df74a81f2 --- /dev/null +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.js @@ -0,0 +1,20 @@ +//// [typeGuardNarrowsIndexedAccessOfKnownProperty11.ts] +enum E { A, B } + +declare const m: { [K in E]: string | null }; + +if (m[E.A] !== null) { + m[E.A].toString(); // string +} + + +//// [typeGuardNarrowsIndexedAccessOfKnownProperty11.js] +"use strict"; +var E; +(function (E) { + E[E["A"] = 0] = "A"; + E[E["B"] = 1] = "B"; +})(E || (E = {})); +if (m[E.A] !== null) { + m[E.A].toString(); // string +} diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.symbols b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.symbols new file mode 100644 index 0000000000000..f97e136634ab3 --- /dev/null +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty11.ts === +enum E { A, B } +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 0)) +>A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 8)) +>B : Symbol(E.B, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 11)) + +declare const m: { [K in E]: string | null }; +>m : Symbol(m, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 2, 13)) +>K : Symbol(K, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 2, 20)) +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 0)) + +if (m[E.A] !== null) { +>m : Symbol(m, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 2, 13)) +>E.A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 8)) +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 0)) +>A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 8)) + + m[E.A].toString(); // string +>m[E.A].toString : Symbol(String.toString, Decl(lib.es5.d.ts, --, --)) +>m : Symbol(m, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 2, 13)) +>E.A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 8)) +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 0)) +>A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty11.ts, 0, 8)) +>toString : Symbol(String.toString, Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.types b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.types new file mode 100644 index 0000000000000..c9ca26e0116d2 --- /dev/null +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty11.types @@ -0,0 +1,30 @@ +=== tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty11.ts === +enum E { A, B } +>E : E +>A : E.A +>B : E.B + +declare const m: { [K in E]: string | null }; +>m : { 0: string | null; 1: string | null; } +>null : null + +if (m[E.A] !== null) { +>m[E.A] !== null : boolean +>m[E.A] : string | null +>m : { 0: string | null; 1: string | null; } +>E.A : E.A +>E : typeof E +>A : E.A +>null : null + + m[E.A].toString(); // string +>m[E.A].toString() : string +>m[E.A].toString : () => string +>m[E.A] : string +>m : { 0: string | null; 1: string | null; } +>E.A : E.A +>E : typeof E +>A : E.A +>toString : () => string +} + diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.js b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.js new file mode 100644 index 0000000000000..0f6a6be2243b6 --- /dev/null +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.js @@ -0,0 +1,23 @@ +//// [typeGuardNarrowsIndexedAccessOfKnownProperty12.ts] +enum E { + A = "A", + B = "B" +} + +declare const m: { [K in E]: string | null }; + +if (m[E.A] !== null) { + m[E.A].toString(); // string +} + + +//// [typeGuardNarrowsIndexedAccessOfKnownProperty12.js] +"use strict"; +var E; +(function (E) { + E["A"] = "A"; + E["B"] = "B"; +})(E || (E = {})); +if (m[E.A] !== null) { + m[E.A].toString(); // string +} diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.symbols b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.symbols new file mode 100644 index 0000000000000..3b4e17f6df88d --- /dev/null +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.symbols @@ -0,0 +1,31 @@ +=== tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty12.ts === +enum E { +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 0)) + + A = "A", +>A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 8)) + + B = "B" +>B : Symbol(E.B, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 1, 12)) +} + +declare const m: { [K in E]: string | null }; +>m : Symbol(m, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 5, 13)) +>K : Symbol(K, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 5, 20)) +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 0)) + +if (m[E.A] !== null) { +>m : Symbol(m, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 5, 13)) +>E.A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 8)) +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 0)) +>A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 8)) + + m[E.A].toString(); // string +>m[E.A].toString : Symbol(String.toString, Decl(lib.es5.d.ts, --, --)) +>m : Symbol(m, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 5, 13)) +>E.A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 8)) +>E : Symbol(E, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 0)) +>A : Symbol(E.A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty12.ts, 0, 8)) +>toString : Symbol(String.toString, Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.types b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.types new file mode 100644 index 0000000000000..37d173c304d23 --- /dev/null +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty12.types @@ -0,0 +1,37 @@ +=== tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty12.ts === +enum E { +>E : E + + A = "A", +>A : E.A +>"A" : "A" + + B = "B" +>B : E.B +>"B" : "B" +} + +declare const m: { [K in E]: string | null }; +>m : { A: string | null; B: string | null; } +>null : null + +if (m[E.A] !== null) { +>m[E.A] !== null : boolean +>m[E.A] : string | null +>m : { A: string | null; B: string | null; } +>E.A : E.A +>E : typeof E +>A : E.A +>null : null + + m[E.A].toString(); // string +>m[E.A].toString() : string +>m[E.A].toString : () => string +>m[E.A] : string +>m : { A: string | null; B: string | null; } +>E.A : E.A +>E : typeof E +>A : E.A +>toString : () => string +} + diff --git a/tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty11.ts b/tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty11.ts new file mode 100644 index 0000000000000..acf01af8cd03b --- /dev/null +++ b/tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty11.ts @@ -0,0 +1,9 @@ +// @strict: true + +enum E { A, B } + +declare const m: { [K in E]: string | null }; + +if (m[E.A] !== null) { + m[E.A].toString(); // string +} diff --git a/tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty12.ts b/tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty12.ts new file mode 100644 index 0000000000000..e426161f08fa0 --- /dev/null +++ b/tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty12.ts @@ -0,0 +1,12 @@ +// @strict: true + +enum E { + A = "A", + B = "B" +} + +declare const m: { [K in E]: string | null }; + +if (m[E.A] !== null) { + m[E.A].toString(); // string +} diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/strictPropertyInitialization.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/strictPropertyInitialization.ts index 3caf731626494..74831b2a730ef 100644 --- a/tests/cases/conformance/classes/propertyMemberDeclarations/strictPropertyInitialization.ts +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/strictPropertyInitialization.ts @@ -150,3 +150,14 @@ class C12 { this['c'] = 1; } } + +enum E { + A = "A", + B = "B" +} +class C13 { + [E.A]: number; + constructor() { + this[E.A] = 1; + } +}