Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#24210: Updated handling of undefined values in Enum types #39390

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34744,6 +34744,9 @@ namespace ts {
Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value);
}
}
else if (initializer.kind === SyntaxKind.Identifier && (initializer as Identifier).escapedText === "undefined") {
return undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't there be an error here? I thought undefined was supposed to be an error, but with an undefined-specific message.

}
else if (enumKind === EnumKind.Literal) {
error(initializer, Diagnostics.Computed_values_are_not_permitted_in_an_enum_with_string_valued_members);
return 0;
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3312,9 +3312,10 @@ namespace ts {
// an identifier that is exported from a merged namespace.
const container = resolver.getReferencedExportContainer(node, /*prefixLocals*/ false);
if (container && container.kind !== SyntaxKind.SourceFile) {
const substitute =
let substitute =
(applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
(applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration);
substitute = substitute && node.escapedText !== "undefined";
if (substitute) {
return setTextRange(
factory.createPropertyAccessExpression(factory.getGeneratedNameForNode(container), node),
Expand Down
75 changes: 75 additions & 0 deletions tests/baselines/reference/enumUndefinedLike.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
tests/cases/conformance/enums/enumUndefinedLike.ts(3,9): error TS18033: Only numeric enums can have computed members, but this expression has type 'Window & typeof globalThis'. If you do not need exhaustiveness checks, consider using an object literal instead.
tests/cases/conformance/enums/enumUndefinedLike.ts(5,9): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
tests/cases/conformance/enums/enumUndefinedLike.ts(5,15): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
tests/cases/conformance/enums/enumUndefinedLike.ts(21,19): error TS2565: Property '"undefined"' is used before being assigned.
tests/cases/conformance/enums/enumUndefinedLike.ts(29,19): error TS2565: Property '"undefined"' is used before being assigned.
tests/cases/conformance/enums/enumUndefinedLike.ts(43,47): error TS2565: Property '"undefined"' is used before being assigned.
tests/cases/conformance/enums/enumUndefinedLike.ts(47,19): error TS2565: Property '"undefined"' is used before being assigned.


==== tests/cases/conformance/enums/enumUndefinedLike.ts (7 errors) ====
enum SomeCombinations {
G = 1,
r = window,
~~~~~~
!!! error TS18033: Only numeric enums can have computed members, but this expression has type 'Window & typeof globalThis'. If you do not need exhaustiveness checks, consider using an object literal instead.
e = undefined,
g = "a" - "a"
~~~
!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
~~~
!!! error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
}

enum TeNormal {
Something = 4
}

enum TeInf {
"Infinity" = Infinity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are Infinity and NaN supposed to be errors or not? Looking at the previous discussion, it seems only intended to be an error for const enum.

}

enum TeNegInf {
"-Infinity" = -Infinity
}

enum TeUndefined {
"undefined" = undefined
~~~~~~~~~
!!! error TS2565: Property '"undefined"' is used before being assigned.
}

enum TeNaN {
"NaN" = NaN
}

enum TeCornerValues {
"undefined" = undefined,
~~~~~~~~~
!!! error TS2565: Property '"undefined"' is used before being assigned.
"NaN" = NaN,
"Infinity" = Infinity,
"-Infinity" = -Infinity,
}

enum TeJoiningAltogether {
"undefined" = NaN + Infinity - Infinity,
}

enum TeJoiningAltogetherWithMemberNameOverlap {
"NaN" = NaN,
"Infinity" = Infinity,
"-Infinity" = -Infinity,
"undefined" = NaN + Infinity - Infinity + undefined,
~~~~~~~~~
!!! error TS2565: Property '"undefined"' is used before being assigned.
}

enum TeJoiningAltogetherWithMemberNameOverlapReverseOrder {
"undefined" = undefined + NaN + Infinity - Infinity,
~~~~~~~~~
!!! error TS2565: Property '"undefined"' is used before being assigned.
"NaN" = NaN,
"Infinity" = Infinity,
"-Infinity" = -Infinity,
}
106 changes: 106 additions & 0 deletions tests/baselines/reference/enumUndefinedLike.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//// [enumUndefinedLike.ts]
enum SomeCombinations {
G = 1,
r = window,
e = undefined,
g = "a" - "a"
}

enum TeNormal {
Something = 4
}

enum TeInf {
"Infinity" = Infinity
}

enum TeNegInf {
"-Infinity" = -Infinity
}

enum TeUndefined {
"undefined" = undefined
}

enum TeNaN {
"NaN" = NaN
}

enum TeCornerValues {
"undefined" = undefined,
"NaN" = NaN,
"Infinity" = Infinity,
"-Infinity" = -Infinity,
}

enum TeJoiningAltogether {
"undefined" = NaN + Infinity - Infinity,
}

enum TeJoiningAltogetherWithMemberNameOverlap {
"NaN" = NaN,
"Infinity" = Infinity,
"-Infinity" = -Infinity,
"undefined" = NaN + Infinity - Infinity + undefined,
}

enum TeJoiningAltogetherWithMemberNameOverlapReverseOrder {
"undefined" = undefined + NaN + Infinity - Infinity,
"NaN" = NaN,
"Infinity" = Infinity,
"-Infinity" = -Infinity,
}

//// [enumUndefinedLike.js]
var SomeCombinations;
(function (SomeCombinations) {
SomeCombinations[SomeCombinations["G"] = 1] = "G";
SomeCombinations[SomeCombinations["r"] = window] = "r";
SomeCombinations[SomeCombinations["e"] = undefined] = "e";
SomeCombinations[SomeCombinations["g"] = "a" - "a"] = "g";
})(SomeCombinations || (SomeCombinations = {}));
var TeNormal;
(function (TeNormal) {
TeNormal[TeNormal["Something"] = 4] = "Something";
})(TeNormal || (TeNormal = {}));
var TeInf;
(function (TeInf) {
TeInf[TeInf["Infinity"] = Infinity] = "Infinity";
})(TeInf || (TeInf = {}));
var TeNegInf;
(function (TeNegInf) {
TeNegInf[TeNegInf["-Infinity"] = -Infinity] = "-Infinity";
})(TeNegInf || (TeNegInf = {}));
var TeUndefined;
(function (TeUndefined) {
TeUndefined[TeUndefined["undefined"] = undefined] = "undefined";
})(TeUndefined || (TeUndefined = {}));
var TeNaN;
(function (TeNaN) {
TeNaN[TeNaN["NaN"] = NaN] = "NaN";
})(TeNaN || (TeNaN = {}));
var TeCornerValues;
(function (TeCornerValues) {
TeCornerValues[TeCornerValues["undefined"] = undefined] = "undefined";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined/NaN/Infinity are still turned into quoted strings. That's not correct, is it?

TeCornerValues[TeCornerValues["NaN"] = NaN] = "NaN";
TeCornerValues[TeCornerValues["Infinity"] = Infinity] = "Infinity";
TeCornerValues[TeCornerValues["-Infinity"] = -Infinity] = "-Infinity";
})(TeCornerValues || (TeCornerValues = {}));
var TeJoiningAltogether;
(function (TeJoiningAltogether) {
TeJoiningAltogether[TeJoiningAltogether["undefined"] = NaN] = "undefined";
})(TeJoiningAltogether || (TeJoiningAltogether = {}));
var TeJoiningAltogetherWithMemberNameOverlap;
(function (TeJoiningAltogetherWithMemberNameOverlap) {
TeJoiningAltogetherWithMemberNameOverlap[TeJoiningAltogetherWithMemberNameOverlap["NaN"] = NaN] = "NaN";
TeJoiningAltogetherWithMemberNameOverlap[TeJoiningAltogetherWithMemberNameOverlap["Infinity"] = Infinity] = "Infinity";
TeJoiningAltogetherWithMemberNameOverlap[TeJoiningAltogetherWithMemberNameOverlap["-Infinity"] = -Infinity] = "-Infinity";
TeJoiningAltogetherWithMemberNameOverlap[TeJoiningAltogetherWithMemberNameOverlap["undefined"] = TeJoiningAltogetherWithMemberNameOverlap.NaN + TeJoiningAltogetherWithMemberNameOverlap.Infinity - TeJoiningAltogetherWithMemberNameOverlap.Infinity + undefined] = "undefined";
})(TeJoiningAltogetherWithMemberNameOverlap || (TeJoiningAltogetherWithMemberNameOverlap = {}));
var TeJoiningAltogetherWithMemberNameOverlapReverseOrder;
(function (TeJoiningAltogetherWithMemberNameOverlapReverseOrder) {
TeJoiningAltogetherWithMemberNameOverlapReverseOrder[TeJoiningAltogetherWithMemberNameOverlapReverseOrder["undefined"] = undefined + TeJoiningAltogetherWithMemberNameOverlapReverseOrder.NaN + TeJoiningAltogetherWithMemberNameOverlapReverseOrder.Infinity - TeJoiningAltogetherWithMemberNameOverlapReverseOrder.Infinity] = "undefined";
TeJoiningAltogetherWithMemberNameOverlapReverseOrder[TeJoiningAltogetherWithMemberNameOverlapReverseOrder["NaN"] = NaN] = "NaN";
TeJoiningAltogetherWithMemberNameOverlapReverseOrder[TeJoiningAltogetherWithMemberNameOverlapReverseOrder["Infinity"] = Infinity] = "Infinity";
TeJoiningAltogetherWithMemberNameOverlapReverseOrder[TeJoiningAltogetherWithMemberNameOverlapReverseOrder["-Infinity"] = -Infinity] = "-Infinity";
})(TeJoiningAltogetherWithMemberNameOverlapReverseOrder || (TeJoiningAltogetherWithMemberNameOverlapReverseOrder = {}));
133 changes: 133 additions & 0 deletions tests/baselines/reference/enumUndefinedLike.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
=== tests/cases/conformance/enums/enumUndefinedLike.ts ===
enum SomeCombinations {
>SomeCombinations : Symbol(SomeCombinations, Decl(enumUndefinedLike.ts, 0, 0))

G = 1,
>G : Symbol(SomeCombinations.G, Decl(enumUndefinedLike.ts, 0, 23))

r = window,
>r : Symbol(SomeCombinations.r, Decl(enumUndefinedLike.ts, 1, 10))
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))

e = undefined,
>e : Symbol(SomeCombinations.e, Decl(enumUndefinedLike.ts, 2, 15))
>undefined : Symbol(undefined)

g = "a" - "a"
>g : Symbol(SomeCombinations.g, Decl(enumUndefinedLike.ts, 3, 18))
}

enum TeNormal {
>TeNormal : Symbol(TeNormal, Decl(enumUndefinedLike.ts, 5, 1))

Something = 4
>Something : Symbol(TeNormal.Something, Decl(enumUndefinedLike.ts, 7, 15))
}

enum TeInf {
>TeInf : Symbol(TeInf, Decl(enumUndefinedLike.ts, 9, 1))

"Infinity" = Infinity
>"Infinity" : Symbol(TeInf["Infinity"], Decl(enumUndefinedLike.ts, 11, 12))
>Infinity : Symbol(TeInf["Infinity"], Decl(enumUndefinedLike.ts, 11, 12))
}

enum TeNegInf {
>TeNegInf : Symbol(TeNegInf, Decl(enumUndefinedLike.ts, 13, 1))

"-Infinity" = -Infinity
>"-Infinity" : Symbol(TeNegInf["-Infinity"], Decl(enumUndefinedLike.ts, 15, 15))
>Infinity : Symbol(Infinity, Decl(lib.es5.d.ts, --, --))
}

enum TeUndefined {
>TeUndefined : Symbol(TeUndefined, Decl(enumUndefinedLike.ts, 17, 1))

"undefined" = undefined
>"undefined" : Symbol(TeUndefined["undefined"], Decl(enumUndefinedLike.ts, 19, 18))
>undefined : Symbol(TeUndefined["undefined"], Decl(enumUndefinedLike.ts, 19, 18))
}

enum TeNaN {
>TeNaN : Symbol(TeNaN, Decl(enumUndefinedLike.ts, 21, 1))

"NaN" = NaN
>"NaN" : Symbol(TeNaN["NaN"], Decl(enumUndefinedLike.ts, 23, 12))
>NaN : Symbol(TeNaN["NaN"], Decl(enumUndefinedLike.ts, 23, 12))
}

enum TeCornerValues {
>TeCornerValues : Symbol(TeCornerValues, Decl(enumUndefinedLike.ts, 25, 1))

"undefined" = undefined,
>"undefined" : Symbol(TeCornerValues["undefined"], Decl(enumUndefinedLike.ts, 27, 21))
>undefined : Symbol(TeCornerValues["undefined"], Decl(enumUndefinedLike.ts, 27, 21))

"NaN" = NaN,
>"NaN" : Symbol(TeCornerValues["NaN"], Decl(enumUndefinedLike.ts, 28, 28))
>NaN : Symbol(TeCornerValues["NaN"], Decl(enumUndefinedLike.ts, 28, 28))

"Infinity" = Infinity,
>"Infinity" : Symbol(TeCornerValues["Infinity"], Decl(enumUndefinedLike.ts, 29, 16))
>Infinity : Symbol(TeCornerValues["Infinity"], Decl(enumUndefinedLike.ts, 29, 16))

"-Infinity" = -Infinity,
>"-Infinity" : Symbol(TeCornerValues["-Infinity"], Decl(enumUndefinedLike.ts, 30, 26))
>Infinity : Symbol(TeCornerValues["Infinity"], Decl(enumUndefinedLike.ts, 29, 16))
}

enum TeJoiningAltogether {
>TeJoiningAltogether : Symbol(TeJoiningAltogether, Decl(enumUndefinedLike.ts, 32, 1))

"undefined" = NaN + Infinity - Infinity,
>"undefined" : Symbol(TeJoiningAltogether["undefined"], Decl(enumUndefinedLike.ts, 34, 26))
>NaN : Symbol(NaN, Decl(lib.es5.d.ts, --, --))
>Infinity : Symbol(Infinity, Decl(lib.es5.d.ts, --, --))
>Infinity : Symbol(Infinity, Decl(lib.es5.d.ts, --, --))
}

enum TeJoiningAltogetherWithMemberNameOverlap {
>TeJoiningAltogetherWithMemberNameOverlap : Symbol(TeJoiningAltogetherWithMemberNameOverlap, Decl(enumUndefinedLike.ts, 36, 1))

"NaN" = NaN,
>"NaN" : Symbol(TeJoiningAltogetherWithMemberNameOverlap["NaN"], Decl(enumUndefinedLike.ts, 38, 47))
>NaN : Symbol(TeJoiningAltogetherWithMemberNameOverlap["NaN"], Decl(enumUndefinedLike.ts, 38, 47))

"Infinity" = Infinity,
>"Infinity" : Symbol(TeJoiningAltogetherWithMemberNameOverlap["Infinity"], Decl(enumUndefinedLike.ts, 39, 16))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlap["Infinity"], Decl(enumUndefinedLike.ts, 39, 16))

"-Infinity" = -Infinity,
>"-Infinity" : Symbol(TeJoiningAltogetherWithMemberNameOverlap["-Infinity"], Decl(enumUndefinedLike.ts, 40, 26))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlap["Infinity"], Decl(enumUndefinedLike.ts, 39, 16))

"undefined" = NaN + Infinity - Infinity + undefined,
>"undefined" : Symbol(TeJoiningAltogetherWithMemberNameOverlap["undefined"], Decl(enumUndefinedLike.ts, 41, 28))
>NaN : Symbol(TeJoiningAltogetherWithMemberNameOverlap["NaN"], Decl(enumUndefinedLike.ts, 38, 47))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlap["Infinity"], Decl(enumUndefinedLike.ts, 39, 16))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlap["Infinity"], Decl(enumUndefinedLike.ts, 39, 16))
>undefined : Symbol(TeJoiningAltogetherWithMemberNameOverlap["undefined"], Decl(enumUndefinedLike.ts, 41, 28))
}

enum TeJoiningAltogetherWithMemberNameOverlapReverseOrder {
>TeJoiningAltogetherWithMemberNameOverlapReverseOrder : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder, Decl(enumUndefinedLike.ts, 43, 1))

"undefined" = undefined + NaN + Infinity - Infinity,
>"undefined" : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["undefined"], Decl(enumUndefinedLike.ts, 45, 59))
>undefined : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["undefined"], Decl(enumUndefinedLike.ts, 45, 59))
>NaN : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["NaN"], Decl(enumUndefinedLike.ts, 46, 56))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["Infinity"], Decl(enumUndefinedLike.ts, 47, 16))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["Infinity"], Decl(enumUndefinedLike.ts, 47, 16))

"NaN" = NaN,
>"NaN" : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["NaN"], Decl(enumUndefinedLike.ts, 46, 56))
>NaN : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["NaN"], Decl(enumUndefinedLike.ts, 46, 56))

"Infinity" = Infinity,
>"Infinity" : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["Infinity"], Decl(enumUndefinedLike.ts, 47, 16))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["Infinity"], Decl(enumUndefinedLike.ts, 47, 16))

"-Infinity" = -Infinity,
>"-Infinity" : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["-Infinity"], Decl(enumUndefinedLike.ts, 48, 26))
>Infinity : Symbol(TeJoiningAltogetherWithMemberNameOverlapReverseOrder["Infinity"], Decl(enumUndefinedLike.ts, 47, 16))
}
Loading