#Discriminated Union type with auto-complete

16 messages · Page 1 of 1 (latest)

crystal matrix
#

Need help specifying type Z that can either be type X or Y, where type X and Y share the same properties but type Y constrains values. Look at the following example:

type Role = 'user' | 'admin'

type Y = { role: Role, id: string | number }
type Z = { role: 'admin', id: string }

type X = Y | Z

This all works great, but if I change type Y specification (e.g., add a new field), TypeScript won't lint and warn that type Z must also be updated. Furthermore, while filing type Z, I can't get auto-complete of known fields in type Y.

Does anybody know a way to create this boundary constraint between type Y and Z?

hallow rose
#

What's the relationship between user and admin? It feels like you are potentially doing it wrong.

crystal matrix
#

that was just an example, don't question the domain logic, I need help on the technical logic x)

hallow rose
#

I'm only asking because you use technical logic to express your domain logic.

#

If what you want to do is to say "user and admin have some shared properties, but admin has a string id whereas user has a number id" then you would express it as:

type Shared = { age: number, whatever: boolean }
type User = Shared & { role: 'user', id: number }
type Admin = Shared & { role: 'admin', id: string }
type Person = User | Admin
#

We can't help you without you telling what you are trying to achieve.

slim wraith
#

Yeah, might be worth clarifying that the original code is not a discriminated union, because role is not distinct between the union members.

#

It's just a normal union and TS doesn't treat normal unions as exclusive.

crystal matrix
#

But I told you what I wanted to achieve:

Need help specifying type Z that can either be type X or Y, where type X and Y share the same properties but type Y constrains values

Furthermore, while filing type Z, I can't get auto-complete of known fields in type Y.

The example you just provided has the same issue as my original code. Type User and Admin have common/shared properties (role and id) but I need to specify them without TypeScript recognizing the common properties. This is bad because I could wrongly type a property name and the final type would not have the right "common properties of X" or "common properties of Y"

I believe what I want to achieve is not possible due to circular type references, but I wanted to double check with people that know better than me

hallow rose
#

This is bad because I could wrongly type a property name and the final type would not have the right "common properties of X" or "common properties of Y"
Can you showcase this with the code I've provided? I don't think it has that issue.

crystal matrix
hallow rose
#

Well there's really not much you can do if you typo role into rolee.

crystal matrix
#

But that's what I want to solve 🙂

hallow rose
#

How would you know rolee is a typo and not just another property that's used by admin?

#

This is a problem better solved by spell checker.

#

I guess alternatively you can do:

type Shared = { role: T, age: number, whatever: boolean }
type User = Shared<'user'> & { id: number }
type Admin = Shared<'admin'> & { id: string }
type Person = User | Admin

But that doesn't solve it if you typo admin into user because you copy pasted either.