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

Narrowing subtypes by enum values does not work #58865

Closed
ivansky opened this issue Jun 14, 2024 · 5 comments
Closed

Narrowing subtypes by enum values does not work #58865

ivansky opened this issue Jun 14, 2024 · 5 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@ivansky
Copy link

ivansky commented Jun 14, 2024

πŸ”Ž Search Terms

"narrow enum", "enum intersection"

πŸ•— Version & Regression Information

  • This is a problem in 5.4.5
  • Have not checked other versions

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/KYDwDg9gTgLgBMAdgVwLZwErAM7CgNwEMYBLCRAYQAtDEBzYAFQE8xg4BvAKDjgqmDFgAEzgBeOAHJ+gmCMkAaHnAAiQ7OKlq52RcoAKhEJsmGQe3gGU8+EgGMcJ6wXs49AXy6hIsBCnRYuATEZJQCQsLUtAwsbJzKMhEmiXLCHl7g0PBIaJg4NiHk2jhR9Eys7Ny8xRoSkjXp3ll+uYEFpORmpTEV8bxmJmaNmb45AfnBHYjOtg7Y3eVxVXAzrrVSq3PpXDC9C9bwEst2NGXYAFx5QURTCwDaALpcnju9bZOhXacMmstgArYIMgLpw7EDEDBLv4AEZ4Ty8RCgSGg8HImFw5S7NiXd43T5GBaxYDPV5xXGFaY2NYLX7KQjCYQiS7YGBQEj0R7KASoCD4JlwFlsjlPXhY4A4iZ48ibErfRbEl5iq7tUI0o7KXiiioS64UwkVDVwdxwABkcAAFIbeAAfZUfcgpEQLK1wW3kqY1Z2azVuyUUr7RYnem12qWUlxzL2agCUXFJ7HdqrlB1pvGEQmZrPZdGUJ0DIMTDrlnPhcHjob14VSar6cDFOpVDqrTrlRJJ5cLiE9ctTcH+wEBwMuHFLiJAyJHmO1FY96n1bHbYMQLIFwBgIP2a8emkeAG44wAzaDmgA2a9X8AgB4v2GjtYA9Pe4HmznASBpEXyoJyLwA6F8MNgzxAA

πŸ’» Code

export enum ReservationChangeType {
  Created = 'Created',
  Dates = 'Dates',
  Pax = 'Pax',
  Services = 'Services',
}
export enum ReservationCreatedChangeType {
  Created = 'Created',
}
export enum ReservationDatesChangeType {
  Dates = 'Dates',
}
export enum ReservationPaxChangeType {
  Pax = 'Pax',
}
export enum ReservationServicesChangeType {
  Services = 'Services',
}

type ChangeSet = {
  changes: ReservationChange[]
}

type ReservationPaxChange = {
  previous: {count: number}
  next: {count: number}
  type: ReservationPaxChangeType
}
type ReservationServicesChange = {
  added: string[]
  removed: string[]
  type: ReservationServicesChangeType
}

type ReservationChange = {
      type: ReservationChangeType
    } & (
      | ReservationCreatedChange
      | ReservationDatesChange
      | ReservationPaxChange
      | ReservationServicesChange
    )

type ReservationChangeSet = {
  date: string
  changes: ReservationChange[]
}
  
type ReservationCreatedChange = {
  type: ReservationCreatedChangeType
}

type ReservationDatesChange = {
  previous: {}
  next: {}
  type: ReservationDatesChangeType
}

const sets: ChangeSet[] = [];

for(let set of sets) {
  // changes is never[]
 set.changes
}

πŸ™ Actual behavior

changes are never[]

πŸ™‚ Expected behavior

changes are narrowed to its subtypes and essentially
ReservationChange[]

Additional information about the issue

If use ReservationChangeType.Created instead of ReservationCreatedChangeType it obviously works,
However it seems it should work even if it two different enums, when their values are intersecting it should not be a problem for narrowing correct type.

@RyanCavanaugh
Copy link
Member

Where are you seeing never[] ? I see ReservationChange[] in the provided playground. There's also no narrowing here.

image

@fatcerberus
Copy link

fatcerberus commented Jun 15, 2024

@RyanCavanaugh I didn't spot this at first either - the Playground code doesn't exactly match the snippet in the OP. If I paste that code into the Playground given, I see the never[].

It seems like OP expects members of different enums with the same underlying string values to be treated as interchangeable, but that's not how enum works. This looks like a clear "working as intended" to me.

@ivansky
Copy link
Author

ivansky commented Jun 17, 2024

I'm sorry, I fixed the link, it should be correct now.

It seems like OP expects members of different enums with the same underlying string values to be treated as interchangeable, but that's not how enum works.

Exactly, thats not how enum works in many languages like Java, where interfaces are also not interchangeable.
However this is Typescript and it has its beauty and freedom to express yourself without having much boundaries around naming.
I was expecting it to work differently. I'm not sure what should be the result, but definitely not never[]

Btw, there are no enums in Javascript, they are converted into objects.

const SomeEnumA = {
  Example: 'Value'
}
const SomeEnumB = {
  Example: 'Value'
}

SomeEnumA.Example === SomeEnumB.Example // correct?

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jun 17, 2024
@RyanCavanaugh
Copy link
Member

The entire point of string enums is to let you have different string primitives with the same value be treated differently. If you don't want that behavior, you should be writing them as consts instead of enums

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants