2

The title sound confusing but here's the gist of it.

I have a User interface that may or may not have some properties depending on from where it's fetched. Here's what I mean: (notice the optional properties role and client_details)

export interface User {
  id: string;
  first_name: string;
  last_name: string;
  email: string;

  // -- One of these in undefined depending on fetch location
  role?: Role;
  client_details?: ClientDetails;
}

The previous approach works, however having an undefined value every time doesn't look very pretty. It would be neeter if I could do this:

export interface User<ExtraType = Role | ClientDetails> {
  id: string;
  first_name: string;
  last_name: string;
  email: string;

  // -- Dynamic property name instead, much cleaner approach
  [ExtraType === Role ? 'role' : 'client_details']: ExtraType;
}

This doesn't work and gives a bunch of errors, mainly A computed property name cannot reference a type parameter from its containing type.

I'm aware I can simply make a static property extra & simply use it every time, but I wanted the property name to somewhat make sense. Is this feasible at all? Thank you!

1 Answer 1

2

What you need here is a disjoint union of types. In your case, it can be done like this:

interface UserBase {
  id: string;
  first_name: string;
  last_name: string;
  email: string;
}
interface UserWithRole extends UserBase {
  role: Role;
  client_details?: undefined;
}
interface UserWithDetails extends UserBase {
  client_details: ClientDetails;
  role?: undefined;
}

export type User = UserWithRole | UserWithDetails;

Now whereever you have a value of type User, you can check it like this:

function test(user: User) {
  if (user.role) {
    // here typescript knows that user is of type UserWithRole
  } else {
    // and here it knows that user is of type UserWithDetails
  }
}

I've added a declaration of missing property (property?: undefined) to both the types so typescript will not complain that User does not always have .role property; you can remove it and see the error in the if (user.role) line.

Here's the complete example

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.