Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(49594): Typescript 4.7.3 bracketed class property compilation err…
…or strictPropertyInitialization:true (#49619)

* fix(49594): allow enum members in computed properties

* add additional tests

* handle enum members without initializers

* update tests
  • Loading branch information
a-tarasyuk committed Sep 26, 2022
1 parent bc9cbbe commit c81bf4d
Show file tree
Hide file tree
Showing 14 changed files with 306 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/compiler/checker.ts
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions tests/baselines/reference/strictPropertyInitialization.errors.txt
Expand Up @@ -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;
}
}

30 changes: 30 additions & 0 deletions tests/baselines/reference/strictPropertyInitialization.js
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -335,3 +357,11 @@ declare class C12 {
['c']: number;
constructor();
}
declare enum E {
A = "A",
B = "B"
}
declare class C13 {
[E.A]: number;
constructor();
}
27 changes: 27 additions & 0 deletions tests/baselines/reference/strictPropertyInitialization.symbols
Expand Up @@ -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))
}
}

32 changes: 32 additions & 0 deletions tests/baselines/reference/strictPropertyInitialization.types
Expand Up @@ -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
}
}

@@ -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
}
@@ -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, --, --))
}

@@ -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
}

@@ -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
}
@@ -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, --, --))
}

@@ -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
}

@@ -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
}
@@ -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
}
Expand Up @@ -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;
}
}

0 comments on commit c81bf4d

Please sign in to comment.