Possible revision: "Dynamic property naming in TypeScript interface based on specified type"

The concept might seem complex, but here's the gist of it.

I have a User interface that may or may not contain certain properties depending on where it is fetched from. For example, there are optional properties like role and client_details.

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

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

The current approach works, but having an undefined value every time isn't ideal. It would be cleaner if I could do this:

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

  // -- Using dynamic property names for a cleaner solution
  [ExtraType === Role ? 'role' : 'client_details']: ExtraType;
}

However, this method throws several errors, particularly

A computed property name cannot reference a type parameter from its containing type
.

While I know I can simply create a static property called extra and use it consistently, I wanted the property name to be more intuitive. Is there a way to achieve this? Thank you!

Answer №1

To achieve what you're looking for, you need to create a disjoint union of types. Here's how you can do it:

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

export type User = UserWithRole | UserWithDetails;

With this setup, whenever you have a value of type User, you can determine its type like this:

function checkUser(user: User) {
  if (user.role) {
    // TypeScript recognizes user as UserWithRole here
  } else {
    // TypeScript recognizes user as UserWithDetails here
  }
}

I included a declaration of the missing property (property?: undefined) in both types to prevent TypeScript from flagging issues where User may not always have a role property. You can try removing it and see the error in the if (user.role) line.

For a complete example, you can visit this link.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

In TypeScript, the type of the second function parameter depends on the type of the first

I'm new to typescript programming. Overview In my typescript react application, I encountered an issue where I needed to dynamically watch the values returned from the watch() method in react-hook-form, based on different parameters passed into a cus ...

Tips for determining if a key is present in local storage:

I need to set a key value, but only if it doesn't already exist. In my component1.ts file, I am assigning the key and value in the constructor. However, I want to include a condition that this action should only be taken if the key is not already pre ...

Angular 2: Assigning a class to a D3 element using the component's style

When creating a component in Angular 2, the `app.component.css` file defines a class called `h-bar`: In the `app.component.ts` file, d3 is utilized to create elements that should apply the `h-bar` class from the `app.component.css` file. d3.select("#cont ...

Error encountered with next-auth and the getServerSession function

Whenever I try to use the getServerSesssion function with all the necessary parameters, it results in a type error. In my code, I have the getServerAuthSession function defined as shown below: import { authOptions } from '@/pages/api/auth/[...nextauth ...

Sending a parameter to a route guard

I've been developing an application that involves multiple roles, each requiring its own guard to restrict access to various parts of the app. While I know it's possible to create separate guard classes for each role, I'm hoping to find a mo ...

Making if-else statements easier

Greetings! I have a JSON data that looks like this: { "details": { "data1": { "monthToDate":1000, "firstLastMonth":"December", "firstLa ...

Issue encountered while deploying Firebase Functions: Unable to parse function triggers

Experiencing difficulty deploying firebase functions from an angular project after updating to the latest firebase-tools 7.8.1 version. The project's package.json contains "firebase-admin": "~6.0.0", "firebase-functions": "^2.1.0", and "firebase-funct ...

Show the subjects' names and their scores once they have been added to a fresh array

Here is my unique code snippet: let fruits: string[] = ['Apple', 'Banana', 'Orange', 'Grapes', 'Mango']; function capitalize(fruit: string) { return fruit.toUpperCase(); } let uppercaseFruits = fruits ...

Having constant problems with ngModel twoway binding. Any suggestions on how to successfully bind to a property in order to update an api link?

I am attempting to implement two-way binding in order to dynamically change the API endpoint when a button is clicked. The value attribute of the button should be used as part of the API URL string. I tried following an example in the Hero Angular App, bu ...

Confirm that a specific value exists within an enumerated set

I am currently using Angular 13.3.9 and typescript 4.6.4. My main objective is to determine if a value is referencing an enum. Below is the code snippet: export enum HttpFunctionalErrorCodes { ACCOUNT_NOT_FOUND = 'ACCOUNT_NOT_FOUND', USER_ ...

TSX implementation of a paginator with an ellipse in the center

Looking to add ellipses in the Pagination, specifically when there are more than 10 pages (e.g., 1 2 3 4 ... 11 12 13 14). I've tried various methods but need guidance as a beginner. Can anyone suggest changes based on my code to help me achieve this? ...

What is the process for defining a default value for a template-driven form input in Angular 2?

I have a simple input element in my form that requires a default initial value to be set. <input type="number" name="interest_rate" [(ngModel)]="interest_rate"> In my code, I included this.form.controls['interest_rate'].patchValue(this.a ...

Error in Typescript: The element is implicitly assigned an 'any' type due to the inability to use a 'string' type expression as an index

I'm a beginner with TypeScript and I encountered an error that's confusing to me while trying to follow an online tutorial on sorting data in Reactjs using React hooks. Here is the section of my component code where the error occurs: Element imp ...

Creating Dynamic Forms in React with Typescript: A Step-by-Step Guide to Adding Form Elements with an onClick Event Handler

I am looking to create a dynamic generation of TextFields and then store their values in an array within the state. Here are my imports: import TextField from '@material-ui/core/TextField'; import Button from '@material-ui/core/Button&apos ...

Angular provides a variety of functionality to control the behavior of elements in your application, including the

I have a page with Play, Pause, Resume, and Stop icons. When I click on the Play icon, the Pause and Stop icons are displayed. Similarly, I would like to show the Resume and Stop icons when I click on the Pause icon. I need help with this code. Thank you. ...

Breaking down an object using symbols as keys in Typescript

I'm encountering an error when running this code Type 'symbol' cannot be used to index type '{ [x: string]: string; }'.: let symbol = Symbol() let obj = { [symbol] : 'value'} let { [symbol]: alias } = obj // ...

Ways to cancel a subscription once a specific parameter or value is met following a service/store interaction

I am working with a service that provides a changing object over time. I need to unsubscribe from this service once the object contains a specific property or later when the property reaches a certain value. In situations like these, I typically rely on t ...

Encountering SUID Sandbox Helper Issue When Running "npm start" on WSL with Electron and Typescript

Can anyone help me with this issue? I have Node v8.10.0 and I'm attempting to follow a beginner tutorial on Electron + Typescript which can be found at the following link: https://github.com/electron/electron-quick-start-typescript Here is the full e ...

Exploring Angular 5: Managing HTTP Headers and Utilizing URL Parameters

I am currently working on an Angular project that involves third-party authentication, which redirects to our app with additional information in the HTTP headers. Here are the questions I have: What is the best way to extract the information from the HT ...

The TS2345 error is triggered when using the fs.readFile function with specified string and

Attempting to utilize the fs.readFile method in TypeScript, my code looks like this... import {readFile} from 'fs'; let str = await readFile('my.file', 'utf8'); This results in the following error message: TS2345: Argumen ...