What is the process for obtaining a literal type from a class property when the class is passed as an argument, in order to use it as a computed property

Just a moment ago I posted this question on Stack Overflow, and now I have a follow-up query :)

Take a look at this code snippet:

import { ClassConstructor } from "class-transformer";
import { useQuery as useApolloQuery } from "@apollo/client";

class Book {
  readonly many = "books" as const;
  bookData: any;
}

export const useQueryWrapper = <T>(cls: ClassConstructor<T>, queryString) => {
  return useApolloQuery<{ [cls.prototype.many]: T[] }>(queryString);
};

const { data } = useQueryWrapper(Book, "..."); // Book or any other class with a literal `many` prop

TypeScript currently recognizes the 'data' variable as:

const data: {} | undefined

I want TypeScript to infer that 'data' should contain a property named 'books'

const data: {
    books: Book[];
} | undefined

Is there a way to achieve this?

Answer №1

To achieve this functionality, a combination of index access types and mapped types can be used (check out the playground):

class Book {
  readonly many = "books" as const;
  bookData: any;
}

class Page {
  readonly many = "pages" as const;
  bookData: any;
}

type ManyType = { readonly many: string };

type QueryResult<T extends ManyType> = {
  // using K in T["many"] to create an object with a key of value T["many"], e.g. "books", "pages", etc.
  [K in T["many"]]: T[]; 
};

type ClassConstructor<T> = new (...args: any[]) => T;

function useQueryWrapper<T extends ManyType>(
  cls: ClassConstructor<T>,
  queryString: string
): QueryResult<T> | undefined {
  return {} as any;
}

const books = useQueryWrapper(Book, "...")?.books; // Book[] | undefined
const pages = useQueryWrapper(Page, "...")?.pages; // Page[] | undefined

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

The use of throwError(error) has been phased out, however, no replacement has been introduced for the Error(HttpErrorResponse)

It seems like the use of throwError(error) is deprecated now. VS Code suggests using throwError(() => new Error('error')) instead, as new Error(...) only accepts strings. How can I replace it correctly without causing issues with my HttpErrorH ...

What is the best way to update multiple data tables using TypeScript?

In my Angular 7 project, I am utilizing TypeScript to implement two data tables on a single page. Each table requires a rerender method in order to incorporate a search bar functionality. While the data tables come with built-in search bars, the sheer volu ...

The creation of a Firebase user account with the specified email and password

I'm currently facing an issue while creating a new user with email and password using firebase authentication. The problem arises when I try to access the displayName from the returned async call before the updateProfile function, as it returns a null ...

TypeScript error message: "The 'new' keyword cannot be used with an expression that does not have a call or construct signature."

Encountered a problem with intersection types in TypeScript... There are three type aliases: Prototype<T> - representing an object or class with a prototype property. DefaultCtor<T> - representing an object or class with a default construct ...

How can one trigger a service method in nestjs through a command?

I am looking to run a service method without relying on API REST - I need to be able to execute it with just one command ...

Is it recommended to include modules in the Imports section of SharedModule in Angular?

Welcome to my SharedModule! import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { IconModule } from "@my-app/components/icon/icon.module"; impo ...

Using TypeORM to update a relation and set it to NULL

My challenge involves managing this specific Entity @Entity({ name: 'orders' }) export class Order { ... @ManyToOne(() => BulkOrder, (bulkOrder) => bulkOrder.orders) bulkOrder?: BulkOrder } In my update process, I am attempting to re ...

In Angular, is there a way to transform time into the format of YYYY-MM-DDThh:mm:ssTZD?

Our backend is built with Java and we are using the ISO 8601 standard for date formatting. In order to pass dates in this format, I require a method to convert the date into the specified format. In Java, we use: DateFormat iso8601 = new SimpleDateFormat( ...

What is the proper way to access the global `angular` variable in Angular and TypeScript when using AngularJS?

I'm currently integrating an Angular 4 component into a large monolithic AngularJS application. The challenge I face lies in the restrictions of the AngularJS project's build system, which limits me to only modifying the project's index.html ...

Error in parsing: An unexpected symbol appeared, an identifier or keyword was expected at the end of the expression

Whenever I attempt to display data from an API, an error always pops up. My goal is to showcase each piece of data individually. To help you analyze the issue, I've included the URL of the API below: civilizationes.component.ts import { Component, O ...

What causes a standard React component with a default render prop to not pass PropTypes validation successfully?

I'm currently working on a React component with a render-prop that has a generic type. To improve usability, I want to set a default value for the render-prop. The code is functioning correctly, but during type-checking, I encountered a warning regard ...

Reactjs may have an undefined value for Object

I have already searched for the solution to this question on stackoverflow, but I am still confused. I tried using the same answer they provided but I am still getting an error. Can someone please help me resolve this issue? Thank you. const typeValue = [ ...

Is app.component.ts necessary in an Angular 2 project?

Currently diving into Angular 2 and have a burning question on my mind. Do I really need the app.component.ts file in my project? Each of my folders has its own component and template, so I'm debating if the main component is necessary or if I can rem ...

Modifying the value of a property in an object array created using the map method is ineffective

I have a collection of objects: https://i.sstatic.net/XNrcU.png Within the collection, I wished to include an additional property to the objects. To achieve this, I utilized the map function: returnArray = returnArray.map((obj) => { obj.active = "fal ...

Issue with VueJS 2 and TypeScript: computed value unable to recognize property specified in data object

When creating the following component: <template lang="html"> <div> <p>{{ bar }}</p> </div> </template> <script lang="ts"> import Vue from 'vue'; export const FooBar = Vue.ex ...

Enhance user experience by enabling clickable links in Angular comment sections

Currently, I'm developing an application that allows users to add comments to specific fields. These comments may contain links that need to be clickable. Instead of manually copying and pasting the links into a new tab, I want the ability to simply c ...

The cause of Interface A improperly extending Interface B errors in Typescript

Why does extending an interface by adding more properties make it non-assignable to a function accepting the base interface type? Shouldn't the overriding interface always have the properties that the function expects from the Base interface type? Th ...

Tips for capturing an error generated by a child component's setter?

I've created an App component that contains a value passed to a Child component using the @Input decorator. app.component.html <app-child [myVariable]="myVariable"></app-child> app.component.ts @Component(...) export class AppC ...

Configuring Jest with TypeScript: A guide to setting up and running tests across multiple files

Currently, I am diving into the world of TDD and attempting to create a basic test suite for my Node Express API. My project directory has the following structure: . └── root/ ├── src/ │ ├── services/ │ │ └─ ...

A guide on instantly updating displayed flat/section list elements in React Native

I am in the process of creating a screen called ContactListScreen. The direct child of ContactListScreen is ContactItems, which is a sectionList responsible for rendering each individual ContactItem. However, I have encountered a problem where my ContactIt ...