Leverage Enum for inferring type from interface

Enum ResourceType contains various resource types such as Blog and BlogAuthor.

enum ResourceType {
  Blog = "blogs",
  BlogAuthor = "blog_authors",
  [...]
}

An interface called ResourceDefinitions stores typings for all resource types:

interface ResourceDefinitions {
  [ResourceType.Blog]: BlogResource;
  [ResourceType.BlogAuthor]: BlogAuthorResource;
  [...]

The goal is to ensure that resource is typed as

BlogResource</code in the following code snippet:</p>
<pre><code>const resource = useResource(ResourceType.Blog, id);

The implementation of useResource function is as follows:

const useResource = <P extends ResourceType, T = ResourceDefinitions[P]>(
  type: P,
  id: string
): T => {
  [...]
};

However, using T = ResourceDefinitions[P] results in error

TS2536: Type 'P' cannot be used to index type 'ResourceDefinitions'.
.

Is there a workaround for this issue?

Two possible solutions are provided below:

The first solution involves manually typing each instance like so:

const useResource = <T>(
  type: ResourceType,
  id: string
): T => {
  [...]
};

const resource = useResource<BlogResource>(ResourceType.Blog, id);

The second solution utilizes the keyof operator to type the resourceType manually:

const useResource = <P extends keyof ResourceDefinitions, T = ResourceDefinitions[P]>(
  type: P,
  id: string
): T => {
  [...]
};

const resource = useResource(ResourceType.Blog as keyof ResourceDefinitions, id);

Answer №1

Upon examination, it appears to function correctly when the unnecessary generic return type is removed:

type BlogResource = { b: 'b' };
type BlogAuthorResource = { ba: 'ba' };

enum ResourceType {
  Blog = "blogs",
  BlogAuthor = "blog_authors"
}

interface ResourceDefinitions {
  [ResourceType.Blog]: BlogResource;
  [ResourceType.BlogAuthor]: BlogAuthorResource;
}

const useResource = <P extends ResourceType>(
  type: P,
  id: string
): ResourceDefinitions[P] => {
  throw new Error();
};

const resource = useResource(ResourceType.Blog, ''); // inferred as BlogResource

Playground link

Answer №2

An issue was encountered where the ResourceDefinitions did not contain all the necessary keys from the enum ResourceType, resulting in the error message

ResourceType cannot be used to index type 'ResourceDefinitions'
. This oversight was not initially evident in my question due to omitted code segments. Apologies for any confusion caused.

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, is it possible to determine an object's type and then enhance it using a type specified through generics?

I am currently working on a TypeScript function that takes an object as a parameter and deduces its type, then merges that inferred type with another type provided via generics. The outcome should be an object that includes properties from both the inferre ...

Utilizing a class structure to organize express.Router?

I've been playing around with using Express router and classes in Typescript to organize my routes. This is the approach I've taken so far. In the index.ts file, I'm trying to reference the Notes class from the notes.ts file, which has an en ...

Issue with ngRX infinite loop caused by the updateOne function in the adapter

Hey there, I'm struggling to figure out why my code is stuck in an infinite loop. I've searched online extensively but haven't found a solution that fits my specific issue. This is the code snippet causing the problem: /** * CODE ...

Encountering an issue where the useMutation function is not recognized on the DecorateProcedure<MutationProcedure> type while attempting to utilize the useMutation feature

Currently, I am utilizing the NextJS app router. I am attempting to invoke a rather straightforward route: import { z } from "zod"; import { createTRPCRouter, publicProcedure } from "~/server/api/trpc"; // document sending user email to waitlist da ...

What is the method for exporting all functions from a TypeScript file with a default export included?

An example of the export type mentioned is React. To use it, we can include the following code: import React, {Component} from "react". This allows us to access both React.Component and Component. What steps are necessary to make this possible? ...

"What is the most efficient way to break up an array into its maximum length and iterate over

Using Firebase to send push notifications, but encountering the following error: { Error: tokens list must not contain more than 500 items at FirebaseMessagingError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42: ...

Add a custom design to the Material UI menu feature

I am currently trying to implement a custom theme using the following code: import Menu from '@material-ui/core/Menu'; import { createStyles, withStyles, Theme } from '@material-ui/core/styles'; const myMenu = withStyles( ( theme: The ...

Exploring React Storybook with TaskHarness

I am facing an issue with my React Storybook. The values on the Docs site are not displaying correctly as expected. https://i.sstatic.net/7WBZx.png The expected output should be: https://i.sstatic.net/zl78e.png with updated values. Below is my compone ...

The 'prop' property is not found within the 'IntrinsicAttributes & CustomComponentProps' type

I developed a custom module with an interface for props, extending props from a file called /types/SharedProps.d.ts. However, when I import this module into a sample project, the extended props are not included in the component. Below is how the module&apo ...

To subscribe to the display of [Object Object], you cannot use an *ngIf statement without being inside an *ngFor loop

In my angular Quiz project, I have a functionality where every user can create quizzes. I want to display all the quizzes that a logged-in user has completed. Here is how I attempted to achieve this: // Retrieving user ID and category ID inside Re ...

Add an additional boolean attribute called `_ro` as a suffix to a property

Is it possible to add an additional property using a property decorator? The current approach I am taking seems to be incorrect. const RoProp = () => { return <T>(target: T, memberName: keyof T) => { const roPropName = `${String(memberNa ...

Guide on generating a typescript type for enabling read-only tuples from a constant value

Here's the interface I'm working with: interface Test { data: string[] } const DATA_LIST = { USER: ["some string"], OTHER: ["some other string", "random value", "etc"] } as const; const test : ...

Navigating the challenges of time zones when calculating lag times

I am currently attempting to calculate the lag in milliseconds between my client (located in France) and my server (based in Germany). On the Client side (Using Angular Typescript) : this.http.getDate().subscribe(response => { if (respo ...

Why does TypeScript not generate an error if props are not passed to a functional component?

How does TypeScript handle not passing down props to a functional component without throwing an error? Consider the following code snippet: interface Props{ id: string; className?: string; } export const Buttons: React.FC<Props> = () => { r ...

Difficulty with the value binding issue on input text produced by *NgFor

When using *ngFor in Angular to loop over an array and generate input text elements bound to the values in the array, I'm encountering some issues. The value is not binding correctly when a user inputs something into the text field. I attempted to ru ...

Having trouble accessing props on children in TypeScript while using React.Children.toArray?

When using React.Children.toArray in Typescript, the props object on children is not detected. In order to address this issue, I am currently using any[] instead of ReactChild[], as props are not recognized on a array item when using the latter. Can someon ...

Is it possible to retrieve cached data from React Query / Tan Stack Query outside of the React tree?

Currently, I am in the process of developing an error handler for our mobile app that will send user data to the server when unexpected errors occur. Previously, I was able to easily retrieve user information from a global state. However, after removing t ...

What is the process of creating an instance of a class based on a string in Typescript?

Can someone please guide me on how to create an instance of a class based on a string in Nestjs and Typescript? After conducting some research, I attempted the following code but encountered an error where it says "WINDOWS is not defined." let paul:string ...

Issue TS2322: The specified type ' ~lib/array/Array<~lib/string/String> | null' cannot be assigned to type '~lib/array/Array<~lib/string/String>'

An array of strings (holder.positions) is stored in Holder. The main purpose of this function is to add the ID of the position parameter to the array. Below is the function used: function updateHolder(holder: Holder, position: Position): void { if(hol ...

Is there a way to utilize Angular in identifying whether a given value corresponds with the value of a particular radio button within my application?

I have an array of lists that I need to display in radio buttons. Like this: https://i.stack.imgur.com/cmYgO.png https://i.stack.imgur.com/Zx4bm.png https://i.stack.imgur.com/jBTe3.png My goal is to have a checkbox that matches the values loaded from a ...