Combine the names of classes in an array into a union type

Can someone help me with extracting all the methods from an Array of Classes into one type Union?

Here's an example:

class A{
  getBooks(): Book[]{}
  getBook(): Book{}
}

class B{
  getUsers(): User[]{}
  getUser(): User{}
  getBooksOfUser(userId: string)Book[]{}
}

I want to create a single type that includes all these methods like this:

type allMethods = "getBooks" | "getBook" | "getUsers" | "getUser" | "getBooksOfUser";

I've tried a few different approaches but can't seem to get it working:

const testResolvers = <const> [A, B]
type ExtractFunctionKeys<T> = { [P in keyof T]-?: T[P] extends Function ? P : never}[keyof T]
export type ValuesOf<T extends any[]>= ExtractFunctionKeys<T[number]>;

type Foo = ValuesOf<typeof testResolvers>;

Any assistance would be greatly appreciated!

Answer â„–1

Two key problems arise in the above approach:

  1. T[number], known as an indexed access type, results in a union of all types within the T tuple/array; however, TypeScript only retains shared keys (intersection) when dealing with variables that are unions. In this case, since A | B lacks common keys, keyof (A | B) is essentially already never, even without method filtering.
  2. When evaluating typeof testResolvers, we actually get readonly [typeof A, typeof B], which assigns the type of the class constructor rather than the actual classes themselves. Consequently, accessing their keys using keyof typeof A, for instance, merely yields "prototype".

Regarding problem 1: instead of a union, what we seek is an intersection wherein TypeScript preserves unioned keys (all keys from any element). While building such an intersection directly from a tuple isn't straightforward, it's feasible with an example like below:

// Transforming a tuple into an intersection of each contained type
type TupleToIntersection<T> =
    T extends readonly never[]
    ? unknown : (
        T extends readonly [infer First, ...infer Rest]
        ? First & TupleToIntersection<Rest>
        : never)

type intersection = TupleToIntersection<typeof testResolvers>
//   ^? type intersection = typeof A & typeof B

In terms of problem 2: to retrieve the class type from its constructor type, one simply needs to access the "prototype" property, generally via indexed access once more. An assistive type could be developed for conditional conversion if needed:

// Extracting the class (prototype) from its constructor if possible
type ConstructorToPrototype<C> = C extends { prototype: infer P } ? P : C

type AClass = ConstructorToPrototype<typeof A>
//   ^? type AClass = A

Subsequently, employing these auxiliary types in line enables us to obtain the desired outcome of extracting the union of methods across all class instances present in the tuple:

// 1. Converting the tuple type into an intersection
// 2. Acquiring the classes over the constructor types
// 3. Retrieving keys with function values (i.e., methods)
type ValuesOf<T extends readonly unknown[]> = ExtractFunctionKeys<ConstructorToPrototype<TupleToIntersection<T>>>;

type Foo = ValuesOf<typeof testResolvers>;
//   ^? type Foo = "getBooks" | "getBook" | "getUsers" | "getUser" | "getBooksOfUser"

Playground 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

What is the best way to link the value of a mat-slider to an input field in a reactive form?

Is there a way to synchronize the min and max values of a ranged mat-slider with corresponding input fields? Currently, when I set numbers in the input fields, the slider updates correctly. However, when I use the slider to change the value of the input fi ...

Leveraging interfaces with the logical OR operator

Imagine a scenario where we have a slider component with an Input that can accept either Products or Teasers. public productsWithTeasers: (Product | Teaser)[]; When attempting to iterate through this array, an error is thrown in VS Code. <div *ngFor= ...

Ensure the proper utilization of properties

Consider a scenario where I have a structure that defines a user along with their login and given name: export interface User { login: string; name: string; } Now, my objective is to make an API call using the user's login information: const fo ...

What steps can I take to prevent receiving the error message "Certain components in XXX are not associated with the entity" in Strapi?

User I am facing an issue with my application's endpoint for adding a like to a post. The endpoint is supposed to receive the user id who liked the post and insert it, along with the number of likes (not crucial at this moment), into a database. To ac ...

Encountered an issue when attempting to include the "for" attribute to a label within an angular 2.0 template

I am currently using Angular 2.0 framework and working on developing an input component. In addition to that, I am also utilizing Google MDL which requires a specific HTML structure with labels for inputs. However, when trying to implement this, I encounte ...

Why do ES6 classes fail to set properties when an overloaded function is called within the constructor of the parent class?

I encountered a puzzling scenario while coding that has left me perplexed. Here's the situation: I am extending a class from a library, which serves as the "Parent"-class. It allows its subclasses to override the init-method for custom initialization ...

Integrating Immutable.js with Angular 2

Looking to optimize performance in your Angular 2 app with immutable.js? Although my app is functioning properly, I am aiming to enhance its performance through optimization and refactoring. I recently discovered immutable.js and want to convert the data ...

Angular form input set to disabled mode

Visit this link for code <form class="example-form"> <mat-form-field class="example-full-width"gt; <mat-label></mat-label> <input matInput placeholder="Ex. Pizza" [disabled]="filterVal ...

Sharing data between two Angular 2 component TypeScript files

I'm facing a scenario where I have two components that are not directly related as parent and child, but I need to transfer a value from component A to component B. For example: In src/abc/cde/uij/componentA.ts, there is a variable CustomerId = "sss ...

I am searching for the vector geometric shapes svg elements that are commonly utilized in design editors. Can you point

When it comes to design editors, there are plenty of options such as Canva, Vistacreate, and Adobe Express. Each one uses a variety of styles for elements/objects/shapes. Are there any databases where I can find these resources? Some popular places include ...

The rapid execution of code causing an observable race condition

When exporting a CSV file in my code, I encounter a race condition while trying to modify some data before the export. The issue is that the id gets set correctly, but the number only updates after the method is called a second time. I believe the proble ...

Performing bulk operations on all selected rows in a table using Angular 6

Within my Angular 6 web application, there is a table with checkboxes in each row. My goal is to be able to perform bulk actions on the selected rows, such as deleting them. One approach I considered was adding an isSelected boolean property to the data m ...

Discovering the method to access a local function within a static function in Javascript ES6 (ES2015) or Typescript

Is there a way to access the non-static "foo2" method from inside the static "bar" method? So far, I'm only able to access the "foo1" and "foo3" methods. Can anyone provide guidance on how to achieve this? let foo1 = () => { alert('foo1†...

TypeScript is throwing an error about a missing property, even though it has been defined

Within the PianoMK1Props component, there is a prop known as recording which accepts an object with specific properties. The structure of this object is defined like so(the state variable): const [recording, setRecording] = useState({ mode: "REC ...

Is there a way to access the value of a public variable within the @input decorator of a function type?

I am working on a dropdown component that utilizes the @Input decorator to define a function with arguments, returning a boolean value. dropdown-abstract.component.ts @Input() public itemDisabled: (itemArgs: { dataItem: any; index: number }) => boo ...

What is the process for modifying href generation in UI-Router for Angular 2?

I am currently working on implementing subdomain support for UI-Router. Consider the following routes with a custom attribute 'domain': { name: 'mainhome', url: '/', domain: 'example.com', component: 'MainSiteC ...

Using TypeScript - Implementing a generic constraint to allow passing a Zod schema result as an argument to a function

I'm in the process of creating a custom controller function to streamline my application. The repetitive task of wrapping try-catch, parsing a zod schema, and merging the request zod schema into a single object is present in all handler functions. The ...

What makes components declared with "customElements.define()" limited in their global usability?

I've been tackling a project in Svelte, but it involves some web components. The current hurdle I'm facing is with web components defined using the customElements.define() function in Typescript, as they are not accessible unless specifically im ...

Tips for dynamically calling a property member of a function type in Typescript

How can I determine if a member is a function in TypeScript? Is dynamic typing discouraged in TypeScript? function checkIfFunction<T, K extends keyof T>(obj: T, propName: K) { if (typeof obj[propName] === "function") { obj[p ...

What is the best way to resolve the unusual resolution issue that arises when switching from Next.js 12 to 13

Previously, I created a website using nextjs 12 and now I am looking to rebuild it entirely with nextjs 13. During the upgrade process, I encountered some strange issues. For example, the index page functions properly on my local build but not on Vercel. ...