Repository navigation
TypeScript silently omits enum assignment type error between two enums with the same name #55915
Description
Activity
DanielRosenwasser commented
on Sep 29, 2023 MemberMore actionsWhat an enormous WAT.
Here is a single-file example:
namespace a { export enum DiagnosticCategory { Warning, Error, Suggestion, Message, } export enum DiagnosticCategory2 { Warning, Error, Suggestion, Message, } } namespace b { export enum DiagnosticCategory { Warning = "Warning", Error = "Error", Suggestion = "Suggestion", Message = "Message", } } function f(x: a.DiagnosticCategory, y: b.DiagnosticCategory) { x = y; y = x; } function g(x: a.DiagnosticCategory2, y: b.DiagnosticCategory) { x = y; y = x; }
and here is one that doesn't use
namespacedeclarations at all:export enum DiagnosticCategory { Warning, Error, Suggestion, Message, } export let x: DiagnosticCategory { enum DiagnosticCategory { Warning = "Warning", Error = "Error", Suggestion = "Suggestion", Message = "Message", } function f(y: DiagnosticCategory) { x = y; y = x; } }
So the context is that ever since TypeScript 1.8(?), a source enum is are compatible with a target enum if its names (the enum declaration and its members) are all identical.
- Enum Equality #1748
- Design Meeting Notes, 11/20/2015 #5740
- Design Meeting Notes for 12/4/2015 #5943
- Compare enums semi-structurally. #6036
I think the weird thing here is that we never checked whether the enum values even though that was explicitly mentioned in the design notes at #5943. I don't know if Nathan Shively-Sanders (@sandersn) knows why that is though.
Part of the issue I think was that people got frustrated over mismatches in numeric enum values. Adding a new member can shift an entire range of enums.
Still, I don't know if I find that all that convincing. Maybe it's a thing about bitflags? But ignoring the values seems extremely wrong.
a source enum is are compatible with a target enum if its names (the enum declaration and its members) are all identical
tl;dr someone took the term "nominal typing" too literally
Reacted by Daniel Rosenwasser, uhyo, Zebulan Stanphill, Jonas and Victorien Elvinger- addedBugA bug in TypeScriptA bug in TypeScriptExperimentation NeededSomeone needs to try this out to see what happensSomeone needs to try this out to see what happens
on Oct 2, 2023 - addedBreaking ChangeWould introduce errors in existing codeWould introduce errors in existing code
on Nov 10, 2023 - addedFix AvailableA PR has been opened for this issueA PR has been opened for this issue
on Nov 17, 2023 - locked as resolved and limited conversation to collaborators
on Oct 22, 2025
🔎 Search Terms
I'm not exactly sure what keywords to use for this because it's kind of a strange problem. Some ideas: enum assignment same name error missing
🕗 Version & Regression Information
⏯ Playground Link
No response
💻 Code
I couldn't do a playground link for this because it requires two separate files:
types.tsdiagnosticInformationMap.generated.ts🙁 Actual behavior
There is no error if you import
DiagnosticCategory as DiagnosticCategory2but there is an error if youDiagnosticCategory2 as DiagnosticCategory2. Mytsconfig.jsonfor this experiment:{ "compilerOptions": { "target": "ESNext", "module": "ESNext", "strict": true } }Demo:
🙂 Expected behavior
I expected importing
DiagnosticCategory as DiagnosticCategory2to cause the same error that importingDiagnosticCategory2 as DiagnosticCategory2does. My rationale is that the two type definitions intypes.tsappear to be identical to me, so my intuition tells me to expect them to behave identically. It seems to me like TypeScript is perhaps silently swallowing the error about assignment compatibility if the two types are named the same thing even though the names refer to two separate incompatible things from two separate files.Additional information about the issue
I discovered this confusing behavior while helping Jake Bailey (@jakebailey) on #55894. It seemed like a bug to me so I'm reporting it here. Feel free to close this issue if this is expected behavior.