Tips on setting interface keys to match a specific union type

I am working with an interface and a union type containing "result types":

export interface ResponseData {
   products: string[];
   content: string[];
} 

export type resultTypes = 'categories' | 'products' | 'content' | 'files';

The resultTypes represent the possible properties of the ResponseData.

I am looking for a way to indicate that the keys in the definition of ResponseData can be dynamic, meaning they must align with one or more of the resultTypes.

I attempted to create another interface that would extend this one, where the keys were dynamic, but unfortunately I was not successful.

In this example, I provide a "typeProp" (of type "resultTypes") to a function expecting a 'keyof ResponseData', resulting in the error:

Argument of type 'resultTypes' is not assignable to parameter of type 'keyof ResponseData'

export interface ResponseData {
   products: string[];
   content: string[];
} 

export type resultTypes = 'categories' | 'products' | 'content' | 'files';

const response: ResponseData = {products: ['r'], content: ['r']}

const currentResultTypes = Object.keys(response) as resultTypes[];

type typeProperty = keyof typeof response;

const hasResultsOfType = (typeProp: typeProperty) => {
  return typeProp in response && response[typeProp];
};

const typeProp = currentResultTypes[0];
const isValid = hasResultsOfType(typeProp);

Answer №1

Considering your grouping of string specific types:

type OutcomeOptions = 'categories' | 'products' | 'content' | 'files';

the structure you are seeking is

interface DataResponse = {
    categories?: string[];
    products?: string[];
    content?: string[];
    files?: string[];
}

where every attribute can be non-mandatory and has a value type of string[].


To automatically derive this from OutcomeOptions, utilize a mapped model with the "?" modifier:

type DataResponse = { [K in OutcomeOptions]?: string[] };
/* type ResponseData = {
    categories?: string[] | undefined;
    products?: string[] | undefined;
    content?: string[] | undefined;
    files?: string[] | undefined;
}*/

This implementation resolves the issue, yet it's defined as a type alias rather than an interface.


If there's a necessity to use an interface, alter the original type first and then incorporate an empty extends clause:

type _ResponseData = { [K in OutcomeOptions]?: string[] };
interface DataResponse extends _ResponseData { }

It would be preferable if we could merge the definition directly into the interface, like

interface DataResponse extends { [K in OutcomeOptions]?: string[] } { } // error    

but due to interface constraints, the above approach won't function.

Fortunately, you still have a solution: {[K in X]?: Y} equals

Partial<Record<X, Y>>
utilizing the Partial and Record utility types... enabling us to employ the named type
Partial<Record<OutcomeOptions, string[]>>
seamlessly:

interface DataResponse extends Partial<Record<OutcomeOptions, string[]>> { }

Access the code on Playground here

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 type 'Promise<any>' cannot be assigned to the type 'Contact[]'

After exhausting all my resources on the internet and StackOverflow, I still couldn't find the right answer. This is my first project in Angular with MongoDB, but I keep encountering this error: "Type 'Promise' is not assignable to type &apo ...

Creating a TypeScript declaration file for a singular module

Consider the following directory structure: src/ ├── foo.ts ├── bar.ts ├── baz.ts ├── index.ts If foo.ts, bar.ts, and baz.ts each export a default class or object, for example in foo.ts: export default class Foo { x = 2; } I ...

Having trouble binding to the *ngFor directive?

I encountered an issue while attempting to utilize the *ngFor directive in my code. Upon running the application, I'm receiving an error message that is puzzling me. I have meticulously verified that all property names are correctly set and there are ...

Vue composable yields a string value

I am currently using a Vue composable method that looks like this: import { ref } from 'vue'; const useCalculator = (num1: number, num2: number, operation: string) => { const result = ref(0); switch (operation) { case 'add& ...

The name 'withStyles' is nowhere to be found

import * as React from "react"; import Button from "@material-ui/core/Button"; import * as PropTypes from "prop-types"; import {WithStyles} from '@material-ui/core'; import "./App.css"; import PageTwo from "./components/PageTwo"; ...

Is there a way to transfer a variable from Angular 2 Frontend Express JS to an Angular 2 component?

After conducting thorough research, I have made specific modifications to my code. However, I am encountering some errors in my console that I cannot seem to resolve. Despite following a tutorial step by step. Your assistance would be highly valued as I a ...

The TypeScript error message indicates that the property 'forEach' is not found on the 'FileList' type

Users are able to upload multiple files on my platform. After uploading, I need to go through each of these files and execute certain actions. I recently attempted to enhance the functionality of FileList, but TypeScript was not recognizing the forEach m ...

Evaluate TypeScript method against the interface, for example T['methodName']

Suppose we have an interface: class A { method(x:number) : string } And a function: const b = (x: string) : number; Our goal is to test the function against the interface. Here is one way to achieve this: type InterfaceKey = { method: any }; ...

Using TypeScript's generic rest parameters to form a union return type

Right now, in TypeScript you can define dynamic generic parameters. function bind<U extends any[]>(...args: U); However, is it possible for a function to return a union of argument types? For example: function bind<U extends any[]>(...args: ...

Is it possible to simultaneously update two entities using a single endpoint?

In order to update data in two different entities with a @OneToOne relationship between UserEntity and DetailsEntity, I need to create a function in my service that interacts with the database. Here are the entity definitions: UserEntity @Entity() export ...

Having trouble sending the request body via next-http-proxy-middleware

Recently, I've been attempting to develop a frontend using nextjs that communicates with a Java backend. To achieve this, I'm utilizing the npm package next-http-proxy-middleware. However, it seems like either my request body is getting lost in t ...

Error: No routes found in Angular 5

I have developed an Angular 5 app and set up the following routing configuration in app-routing.module.ts file: import { ControlPanelComponent } from './dashboard/control-panel/control-panel.component'; import { MainComponent } from './dash ...

Issue encountered with react-toolbox 2.0-beta.6's ThemeProvider not functioning as expected

I have been attempting to modify the color-primary and color-accent variables in react-toolbox using react-toolbox-themr, but without success. I have created a simple git repository to showcase this issue. Below is my react-toolbox-themr.config.json: { ...

Destructuring an array of strings for use as parameters

Hey guys, I'm working with an array of keys here Example 1: let keyArray = ['x', 'y', 'z'] I'm trying to find a way to use these keys as parameters without repeating them multiple times. Do you have any suggestions ...

Incorporate SVG files into a TypeScript React application using Webpack

I am trying to incorporate an SVG image into a small React application built with TypeScript and bundled using Webpack. However, I am encountering an issue where the image is not displaying properly (only showing the browser's default image for when n ...

What is the best way to leverage TypeScript for destructuring from a sophisticated type structure?

Let's consider a scenario where I have a React functional component that I want to implement using props that are destructured for consistency with other components. The component in question is a checkbox that serves two roles based on the amount of ...

Tips for assigning a preset value to a checkbox

Is there a simple way to set the default Checked value of this angular checkbox? <p class="card-text">Please let me know which public organizations have been notified.</p> <div for="stakeholders" class="custom-control custom-c ...

Choosing a single element through viewChild using the "#" selector in Angular 2

Is there a special method to choose multiple tags on the same level with the same tag? <div #el></div> <div #el></div> <div #el></div> I keep getting an error message that says "Reference "#el" is defined several times ...

Issue encountered with the signature provided for a Safe API POST request

Watch this demonstration video of the issue at hand: I have created a signer using my Metamask Private Key and generated a signature from it as shown below: const signer = new ethers.Wallet(PRIVATE_KEY as string, provider) const safeInstance = new ethers. ...

Typescript not being transpiled by Webpack

As I set out to create a basic website, I opted to utilize webpack for packaging. TypeScript and SASS were my choice of tools due to their familiarity from daily use. Following the documentation at https://webpack.js.org, I encountered issues with loaders ...