Maintaining consistency between two fields? Foo<X> (x:X leads to y:Y)

Is there a way to establish a relationship between two types in Typescript? For instance, I need to ensure that the TypeContent in the example below is appropriate for the type T.

export type DataReport<T extends Type, TypeContent> = {
  id: number
  createdAtDateTime: Iso8601DateTime
  contentType: T
  content: TypeContent // should depend on T somehow
}

If we were using a JavaScript map, it might look something like this:

TypeMap = {
   Questionnaire: { id: string, items: QuestionnaireItem[] }
   BloodSample:  { dueDate: Iso8601DateTime }
}

const TypeContent = TypeMap[Type] // Type = BloodSample or Questionnaire

Can this concept be translated into TypeScript effectively?

Answer №1

If you want to create a type map in TypeScript, you can achieve this by utilizing indexed access types.

type TypeMap = {
  Questionnaire: { id: string, items: QuestionnaireItem[] }
  BloodSample:  { dueDate: Iso8601DateTime }
}

type Types = keyof TypeMap

export type DataReport<T extends Types> = {
  id: number
  createdAtDateTime: Iso8601DateTime
  contentType: T
  content: TypeMap[T]
}

type Test = DataReport<'Questionnaire'>
// => 
{
    id: number;
    createdAtDateTime: Iso8601DateTime;
    contentType: "Questionnaire";
    content: {
        id: string;
        items: QuestionnaireItem[];
    };
}

Check out the code snippet on TS Playground

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

Angular 2 and .NET Core 2.0 triggering an endless loop upon page refresh detection

My application, built with dotnet core 2.0 and angular 2, allows me to view member details. The process begins with a list page displaying all the members from a SQL Server database. Each member on the list has a link that leads to an individual details pa ...

Example of a floating undo bar using a dynamic function in a Vuex store module

Issue Overview Trigger the mutation or action of Vuex store module A to execute an external function. This external function can belong to another Vuex store module (e.g. B). A should store a reference to the external method (e.g. mutation or action from ...

What is the best way to choose a particular radio button from a group of radio buttons using typescript?

Is there a way to automatically select a specific radio button when an item is chosen from a dropdown menu on the webpage using a TypeScript function that is triggered by the dropdown selection? ...

Upon running `npm run build` in vue.js, an error occurs stating that the interface 'NodeRequire' cannot extend types 'Require' simultaneously

ERROR in C:/phpStudy2018/PHPTutorial/WWW/Tms.Web/node_modules/@types/node/globals.d.ts(139,11): 139:11 The 'NodeRequire' interface cannot extend both 'Require' and 'RequireFunction' at the same time. The named property &apos ...

Is there a way to customize the scrollbar color based on the user's preference?

Instead of hardcoding the scrollbar color to red, I want to change it based on a color variable provided by the user. I believe there are two possible solutions to this issue: Is it possible to assign a variable to line 15 instead of a specific color lik ...

The reducer within ngrx/store fails to trigger

In my project using combineReducers with "@angular/core": "4.4.3" and "@ngrx/store": "4.0.3", I am facing an issue where the reducers are not being detected after dispatching the actions. It could be due to my lack of experience with ngrx/store. You can ...

An interface that is extended by an optional generic parameter

I currently have an exported abstract class that has one generic. However, I now require two generics. I do not want to modify all existing classes that are using this class. Therefore, I am looking to add an optional generic class that extends an interfac ...

Filtering an array in Angular based on two specific property values

I am facing a challenge with deleting items from an array based on two property values. If we were to compare it to the classic Sql delete command, the equivalent would look something like this: DELETE oImages WHERE idOffertRow = 1 and idProductImage = 2 ...

How can I achieve a result using a floating label in a .ts file?

I'm facing a simple issue that I can't seem to figure out. The problem is with a floating label in my HTML file, as shown below: <ion-list> <ion-item> <ion-label floating >Username</ion-la ...

Code in Javascript to calculate the number of likes using Typescript/Angular

I have encountered a challenge with integrating some JavaScript code into my component.ts file in an Angular project. Below is the code snippet I am working on: ngOninit() { let areaNum = document.getElementsByClassName("some-area").length; // The pr ...

Guide on sending a message to a specific channel using Discord.js version 13 with TypeScript

After recently diving into TypeScript and seeing that Discord.js has made the move to v13, I have encountered an issue with sending messages to a specific channel using a Channel ID. Below is the code snippet I am currently using: // Define Channel ID cons ...

Encountering Typescript problem following the upgrade to create-react-app 4.0.0

After updating create-react-app to version 4.0.0, I faced several issues. The first one being: TypeError: Cannot add property noFallthroughCasesInSwitch, object is not extensible To resolve this, I added "noFallthroughCasesInSwitch": true, to m ...

What causes the failure of $event binding when using RowGroup tables with PrimeNG?

I have successfully implemented RowGroup to store 3 different tables, which is working great. However, I am facing an issue with the onRowSelect function not functioning properly. When I click on any row of the RowGroup tables, nothing happens. On another ...

Experiencing Trouble with Dependency Injection in Angular 5

I'm encountering an error in my angular 5 application ("@angular/core": "5.1.2") and need some assistance. Uncaught Error: Can't resolve all parameters for FooComponent: (?). Service: @Injectable() export class FooService { } Component: @C ...

Is there a specific type required for the Vue `install` function? Is it necessary to have the `directive` property on the `Vue`

I've been working on implementing a Vue directive in typescript, but I'm struggling to determine the correct types to use for the Vue install function. Using install(Vue: any): void feels a bit strange to me. I attempted importing Vue and using ...

What is the best approach for injecting services (local and API) in Angular 13 based on different environments (local and QA)?

api-local.service.ts import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { LoginRequest } from '../login/login-request'; @Injectable({ providedIn: 'root&ap ...

What steps can I take to resolve the 'Object may be null' error in TypeScript?

I am facing a similar issue to the one discussed in this thread, where I am using Draft.js with React and Typescript. After following the code example provided in their documentation, I encountered the 'Object is possibly 'null'' error ...

Unable to assign user roles in next-auth due to the absence of matching modifiers for user

I am currently working on implementing user roles in next-auth. Within my database, I have defined a prisma enum UserRole with the values 'ADMIN' and 'USER'. In my auth.ts file, I included the role property in the session object and enc ...

Resolving the problem of <Link> error in React with Typescript using react-router-dom

Currently, I am facing an issue with the 'react-router-dom' library. This is my first experience using React with Typescript; Everything was functioning properly until I introduced the from 'react-router-dom', which caused the entire ...

Using Angular service within InnerHTML functions

Within my Angular 10 application, I am utilizing innerHtml to display some content that includes anchor links. My goal is to trigger a function every time a link is clicked, which will then invoke an Angular service. In the code snippet below, I am attac ...