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 data type 'string' cannot be assigned to the data type 'Position'

Currently, I am in the process of converting React js to typescript. The component being used is a Class Component. I would like to obtain CSS settings through props and apply them to an element. How can I resolve this issue? render(){return( <span st ...

Facing problem with implementing NgMoudleFactoryLoader for lazy loading in Angular 8

A situation arose where I needed to lazy load a popups module outside of the regular router lazy-loading. In order to achieve this, I made the following adjustments: angular.json "architect": { "build": { ... "options": { ... "lazyM ...

Error encountered when trying to use the .find function in Typescript: "The expression is not callable."

Environment Details: typescript 4.5.5 Error Summary An issue occurred stating: "This expression is not callable. Each member of the union type '{ <S extends User>(predicate: (this: void, value: User, index: number, obj: User[]) => value ...

``If you're looking to integrate a 360-degree product viewer into your Angular application, here is a

I am in need of showcasing a 360 Product viewer consisting of an array of 36 car images in base64 format. Despite attempting to utilize the angular-three-sixty Package by @mediaman, I was only met with an empty canvas. Does anyone have experience in implem ...

By constantly subscribing to a Behavior Subject, updating the data, and then resetting the value, an endless loop is created

We have implemented a wizard functionality with lazy loading, consisting of a parent component and multiple child components. const routes: Routes = [ { path : '', component : WizardHomeComponent, canActivate: [HomeGuard], chil ...

Unable to retrieve values using any = {} in TypeScript Angular 8

import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { enableProdMode } from '@angular/core'; enableProdMode(); @Component({ selector: 'app-home', templat ...

ngPrime table column selection and data extraction

I am looking to extract multiple columns from a table. Can anyone suggest the best approach for this? Does NGPrime offer any functionality for achieving this task? Appreciate your help! ...

typescript - instantiate an object using values stored in an array

Assume we have a model defined as follows. export interface Basicdata { materialnumber: number; type: string; materialclass: string; } We also have an array containing values that correspond directly to the Basicdata model in order, like this: ...

Maximize the benefits of using React with Typescript by utilizing assignable type for RefObject

I am currently working with React, Typescript, and Material UI. My goal is to pass a ref as a prop. Within WidgetDialog, I have the following: export interface WidgetDialogProps { .... ref?: React.RefObject<HTMLDivElement>; } .... <div d ...

What is the best way to apply ngClass to style a JSON object based on its length?

Currently, I am working with a mat-table that displays data from a JSON object. My goal is to filter out all records with an ID of length 5 and then style them using ngClass in my HTML template. How can I achieve this? Below is the code I am working with: ...

Enhance your text in TextInput by incorporating newline characters with advanced editing features

I'm encountering an issue with my Textarea component that handles Markdown headers: type TextareaProps = { initValue: string; style?: StyleProp<TextStyle>; onChange?: (value: string) => void; }; type OnChangeFun = NativeSynthetic ...

An error has occurred in Typescript stating that there is no overload that matches the call for AnyStyledComponent since the update to nextjs

Upgraded to the latest version of nextjs, 13.3.1, and encountered an error in the IDE related to a styled component: Received error TS2769 after the upgrade: No overload matches this call. Overload 1 of 2, '(component: AnyStyledComponent): ThemedSty ...

Does the router navigate function instantly update the router URL?

I'm testing whether the navigate function will immediately alter the router URL upon execution. this.router.navigate(['/home/products']); if (this.router.url.includes('/home/products')) console.log('URL has been changed&apos ...

@ngrx effects ensure switchmap does not stop on error

Throughout the sign up process, I make 3 http calls: signing up with an auth provider, creating an account within the API, and then logging in. If the signup with the auth provider fails (e.g. due to an existing account), the process still tries to create ...

Printing from a lengthy React DOM using window.print only generates a single page

My React component is capable of rendering markdown and can span multiple pages. Everything looks great when the component is displayed in the browser - scrolling works perfectly. However, whenever I try to print the page using window.print or ctrl + P, ...

The error message "TypeError: Unable to access the 'getFullWidth' property of an undefined value when using TSLint and TypeScript" was

I have been using Dan Wahlin's tutorials and online examples to set up Gulp and Typescript, but I am facing an issue with the tslint() function. The problem occurs in my code as follows: node_modules\tslint\lib\language\walker&bso ...

In TypeScript, Firestore withConverter may return a QueryDocumentSnapshot instead of the expected Class object

I'm currently exploring the usage of Firestore's withConverted method in Typescript to retrieve queries as instances of my customized class. Custom EventConverter Class import Event from "@/models/Event"; class EventConverter implemen ...

Submitting Data in Ionic 3 using Http Post and Storing in Sqlite with Angular 4

I am facing an issue while trying to post an array of contacts on a WebService. When I send the array, the data appears as NULL in the WebService response. I am confused about how to use Let params{} The error message shows "object undefined". Addition ...

Difficulties with managing button events in a Vue project

Just getting started with Vue and I'm trying to set up a simple callback function for button clicks. The callback is working, but the name of the button that was clicked keeps showing as "undefined." Here's my HTML code: <button class="w ...

How to apply dynamic styling to a MatHeaderCell using NgStyle?

My goal is to dynamically style a MatHeaderCell instance using the following code: [ngStyle]="styleHeaderCell(c)" Check out my demo here. After examining, I noticed that: styleHeaderCell(c) It receives the column and returns an object, however ...