An issue arises when attempting to retrieve various Modules depending on the specific type of Module that is provided

My goal is to pass an array of different types to generate various combinations of submodules.

However, I am currently only passing a single type which works fine. When I try to pass multiple types, the compilation fails.

What steps can I take to resolve this issue?

export enum Module {
  'Video' = 0,
  'Chat',
}

export interface ModulesMaps {
  [Module.Video]: VideoModule;
  [Module.Chat]: ChatModule;
}

export interface VideoModule {
  getVideoModule():  string;
}

export interface ChatModule {
  getChatModule():  string;
}

export interface CommonModule {
  init(): void;
}

export type Core<T extends Module> = CommonModule & ModulesMaps[T]

export function createClient<T extends Module>(modules: T[]): Core<T>{
  // fake code
  return undefined as unknown as Core<T>;
}

let client1 = createClient([Module.Video]);
client1.getVideoModule();
client1.init();

let client2 = createClient([Module.Chat]);
client2.getChatModule();
client2.init();

let client3 = createClient([ Module.Chat | Module.Video  ]);
client3.getVideoModule(); //compile error
client3.getChatModule(); //compile error
client3.init();

Playground : typescriptlang.org playground

I want to pass in an array of different types so that I can get different combinations of submodules.

But I pass in a single type which is fine, and when I pass in multiple types, it compiles incorrectly.

How do I change this?

Answer №1

When rewriting the code snippet as:

export type Core<T extends Module> = CommonModule & { foo: ModulesMaps[T] }
export function createClient<T extends Module>(modules: T[]): Core<T> & unknown {
  throw 0;
}
let client3 = createClient([Module.Chat, Module.Video]);
// let client3: CommonModule & {
//     foo: VideoModule | ChatModule;
// }

You may notice a union being used instead of an intersection. To make it work properly, you need to change it to an intersection.

// Either add this package as a dependency or copy-paste the needed types. No credit required.
// https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts
import { UnionToIntersection } from 'type-fest'

export type Core<T extends Module> = CommonModule & UnionToIntersection<ModulesMaps[T]>
export function createClient<T extends Module>(modules: T[]): Core<T> & unknown {
  // `& unknown` unwraps `Core<Module>` into `CommonModule & VideoModule & ChatModule`
  // this is for understandability, feel free to remove it for production
  throw 0;
}
let client3 = createClient([Module.Chat, Module.Video]);
// let client3: CommonModule & VideoModule & ChatModule

Answer №2

Gratitude to @Dimava for helping me find two solutions.

1. Leveraging UnionToIntersection from the type-fest library by @Dimava

// Code block here

playground link

2. Implementation using tuple types

// Another code block here

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

Can a mapped union type be created in TypeScript?

Can the features of "mapped types" and "union types" be combined to generate an expression that accepts the specified interface as input: interface AwaActionTypes { CLICKLEFT: 'CL'; CLICKRIGHT: 'CR'; SCROLL: 'S'; ZOOM ...

angular 2 updating material table

Issue at Hand: I am facing a problem with the interaction between a dropdown menu and a table on my website. Imagine the dropdown menu contains a list of cities, and below it is a table displaying information about those cities. I want to ensure that whe ...

Global variable appears undefined in Angular 2 view, yet it is still displaying

I'm running into issues with my Angular 2 code. Inside my ts file, I have the following: import { Test } from '../../../../models/test'; import { TestService } from '../../../../services/test.service'; import { Job} fr ...

having difficulty sending a post request with Angular

Submitting form data via HTTP post will look like this: saveDataFile(mutlidata,id,value): Observable<Response> { var _url = 'http://xxxx.xxx.xxx'; var saveDataURL = _url + '/' + id; var _this = this; ...

What is the proper way to reference a computed symbol that has been inherited as a function in an extended class

As a newcomer to Typescript, my understanding of the code might be lacking. I am currently working with the Klasa framework, which is built on top of Discord bot framework using Discord.js. The framework recently introduced plugin functionality and there a ...

The argument of type 'NextRouter' cannot be assigned to the parameter of type 'Props' in this scenario

In my component, I am initializing a Formik form by calling a function and passing the next/router object. This is how it looks: export default function Reset() { const router = useRouter(); const formik = useFormik(RecoverForm(router)); return ( ...

Unable to start an expo project in bare workflow using TypeScript

Can someone help me with setting up an expo bare workflow using TypeScript? I ran the command "expo init [project name]" in my terminal, but I can't seem to find the minimal (TypeScript) option. ? Choose a template: » - Use arrow-keys. Return to sub ...

Error message "Property 'name' does not exist on type '{}'" is encountered when using Ionic/Angular HttpClient and no data type is specified

While working on my Ionic project, I encountered an error in Angular when trying to fetch data from an API using HttpClient. The error message that popped up was 'Property 'name' does not exist on type '{}'.'. Below is the cod ...

The element cannot be clicked at the specified point in Protractor while using TypeScript

I've been struggling with this code and can't seem to get it to click the element or stop throwing errors. Can someone please help me correct this code? async testMethod() { let button = element( by.cssContainingText('span.mat-button-wr ...

What is the process for enabling keyboard selections in a Material-UI Select component?

Is there a way to make the MUI Select component keyboard accessible by tabbing into it and using the first letter of the option to auto-select without opening the list? I am looking for a feature where pressing the initial letter selects the first item tha ...

The property 1 cannot be added because the object is not extendable in React

Does anyone know what is causing the following issue? I am unable to insert a new object into a key object within my arrays of objects. For example, when I try to insert a new email at index 1 in the 'emails' array, it throws an error stating "ca ...

Encountering NaN in the DOM while attempting to interpolate values from an array using ngFor

I am working with Angular 2 and TypeScript, but I am encountering NaN in the option tag. In my app.component.ts file: export class AppComponent { rooms = { type: [ 'Study room', 'Hall', 'Sports hall', ...

Exploring the functionalities of React Native with react-hook-form and implementing them with TypeScript

I've been working on creating a custom Input component in react native using typescript for the react-hook-form library. type CustomInputProps = { name: any, control: any } const CustomInput: FC<CustomInputProps> = ({name, control, ...p ...

Guide to encoding an array of objects into a URI-friendly query string using TypeScript

Just getting started with typescript and looking for some help. I have an input array structured like this: filter = [ { field : "eventId", value : "123" }, { field : "baseLocation", value : "singapore" } ] The desired format for ...

Managing null values in RxJS map function

I'm facing a scenario where my Angular service retrieves values from an HTTP GET request and maps them to an Observable object of a specific type. Sometimes, one of the properties has a string value, while other times it's null, which I want to d ...

Ensure the JSON file aligns with the TypeScript Interface

I am working with a config.json file. { "profiler": { "port": 8001, "profilerCache": { "allowedOriginsRegex": ["^http:\/\/localhost:8080$", "i"] } }, "database": { "uri": "mongodb+srv://...", "dbName": "profiler", ...

Exploring the application of keyof with object structures instead of defined types

Looking to create a new type based on the keys of another object in TypeScript. Successfully achieved this through type inference. However, using an explicit type Record<string, something> results in keyof returning string instead of a union of the ...

Is the type check being disregarded within the loop?

I encountered this issue while working with a React component: if (props.someArray){ // I need to typecheck because someArray is of type 'things[] | undefined' props.someArray.forEach((element, i) => { someFunction(i, elem ...

Guide for converting a JavaScript function with spread arguments of different types to C# style

I am having difficulty with the strict typing in C# when it comes to function arguments. For my Reverse Polish Notation (RPN) calculator, the required arguments will be passed through a function call using a comma-separated list of different types: this.F ...

What is the best way to incorporate an Angular template to verify if a particular array includes an object with a property that matches a specific value?

I am currently working with Angular and have encountered the following scenario: <div *ngIf="myarrayContainsEating('Chocolate')">Chocolate Is Good</div> Within my component, I have defined an array as follows: myarray = [{'nam ...