Guide to building a static method generator in TypeScript

Currently, I am working on creating a static method factory function in TypeScript. In my previous implementation using ES6, everything was functioning well and meeting my expectations. However, upon transitioning to TypeScript, I encountered a type-casting issue that needs to be resolved. If you have any suggestions on how to fix this problem or propose a different design approach, I would greatly appreciate your assistance.

Javascript

REPL: https://repl.it/@RenjithV/NeatTepidBugs

class EventController {
  static create () {
    console.log('event created')
  }
}

class MessageController {
  static read () {
    console.log('message read')
  }
}

const controllers = {
  'event': EventController,
  'message': MessageController
}

function factory (controller, method) {
  return controllers[controller][method]() // Operating as expected
}

const createEvent = factory('event', 'create') // event created
const readMessage = factory('message', 'read') // message read

TypeScript

REPL: https://repl.it/@RenjithV/EuphoricFeistyUtility

class EventController {
  static create () {
    console.log('event created')
  }
}

class MessageController {
  static read () {
    console.log('message read')
  }
}

const controllers = {
  'event': EventController,
  'message': MessageController
}

function factory (controller: string, method: string) {
  return controllers[controller][method]() // Seeking solution for typecasting issue here
}

const createEvent = factory('event', 'create')
const readMessage = factory('message', 'read')

Answer №1

class EventController {
  public static create () {
    console.log('event created')
    return true
  }
}

class MessageController {
  public static read () {
    console.log('message read')
  }
}

type Controllers = {
    event: typeof EventController
    message: typeof MessageController
}
type OnlyStatic<T> = Exclude<T, 'prototype'>

const controllersMap: Controllers = {
  'event': EventController,
  'message': MessageController
}

function callFunctionByType<K extends keyof Controllers, M extends OnlyStatic<keyof Controllers[K]>>(controllerKey: K, methodKey: M): Controllers[K][M] {
  return controllersMap[controllerKey][methodKey]
}

const createEventFunction = callFunctionByType('event', 'create')
const readMessageFunction = callFunctionByType('message', 'read')

const booleanResult = createEventFunction()

Demo

Brief explanation

// generic calling is not allowed as typescript
// doesn't yet know what arguments you gonna pass to factory
// return actual function instead of function return value
controllersMap[controllerKey][methodKey]

// extending typescript Exclude utility
// removes prototype key from string union
// because class by default has static prototype method
// Exclude<"some" | "other", "other"> => "some"

type OnlyStatic<T> = Exclude<T, 'prototype'>

// assign keys of Controllers to K
// "event", "message"
K extends keyof Controllers

// assign keys of EventController if K is "event"
// assign keys of MessageController if K is "message"
M extends OnlyStatic<keyof Controllers[K>

Suggestion

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 method for extracting user input from a text box on a webpage?

Having trouble with retrieving the value from a text box in my search function. SearchBar Component import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-search', templateUrl: './search.compon ...

Using Jasmine to Jest: Mocking Nested function calls

I am currently working on testing my TypeScript functions with Jasmine: //AB.ts export async function A() { } export async function B() { A(); } My goal is to unit test function B by mocking out function A to see if it is called. Here is the code I h ...

Encountering the error "tsx is not defined" during a Jest test in a React/TypeScript project

I'm currently working on implementing Jest tests within a React project that has enforced TypeScript settings. In a simple test.tsx file located in the test folder, I have the following code: import React from 'react'; describe('Test& ...

Steps for incorporating a type declaration for an array of objects in a React application with TypeScript

How can I specify the type for an array of objects in React using TypeScript? Here is the code snippet: const SomeComponent = (item: string, children: any) => { //some logic } In this code, you can see that I am currently using 'any' as ...

Ways to convert a callback-based function into a promise without losing the returned value

After being given access to this API: function doSomeWork(callbacks : { success ?: (result : SuccessCallbackResult) => void, fail ?: (result : FailCallbackResult) => void, complete ?: (result : CompleteCallbackResult) => void }) : Task ...

Playwright failing to execute GraphQL tests due to TypeScript configuration problems

I'm facing an issue with my repo where I am running tests using Playwright against a graphQL URL. Despite configuring the tests, there is an error indicating that the environment variable defining the environment cannot be found. The repository in qu ...

Type-safe Immutable.js Records with TypeScript

I'm struggling to find a suitable solution for my query. I am aiming to define data types using an interface in TypeScript, but my data consists of Immutable.js records making it more complex. Please refer to the example provided below. interface tre ...

What is the proper way to utilize a custom property that has been incorporated into my Pinia stores in a Typescript project?

Currently utilizing Vue 3 alongside Pinia; my api service is utilized for making requests to the api. I have included it as a property to ensure availability across all stores: In my main.ts file: import { http } from "@/services/http"; const s ...

Can you explain the contrast between Angular 2 components and directives?

I have been having difficulty grasping the distinction between these two ideas within the framework. I am quite experienced with directives in AngularJS 1.x, and both components and directives in Angular 2 appear to be closely related to this concept... ...

Unable to modify the active property of the specified object as it is read-only

Presented here is the interface: export interface ProductCommand extends ProductDetailsCommand { } This is the ProductDetailsCommand interface: export interface ProductDetailsCommand { id: string; active: boolean; archive: boolean; title: ...

Issue with passing props to child component in React due to TypeScript error

In the process of developing an expense tracker app using react and typescript. expense_type.ts export type IState = { id : number, text : string, amount : number } export type IinitialStateType = { transactions : IState[] } expor ...

Encountering a TypeScript error when using Redux dispatch action, specifically stating `Property does not exist on type`

In my code, there is a redux-thunk action implemented as follows: import { Action } from "redux"; import { ThunkAction as ReduxThunkAction } from "redux-thunk"; import { IState } from "./store"; type TThunkAction = ReduxThunk ...

Looking for a way to dynamically append a child element within another child

Struggling to include a new child within a specific child in Json myObject:any[] = []; this.myObject = { "type": "object", "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, } } addF ...

Using NextJS: Issue with updating Value in useState

In my current project, I am attempting to display a string that changes when a button is pressed in my NextJs application. Here's the code snippet I am working with: 'use client' import { useState } from 'react' export default fu ...

What could be the reason for the form value object being devoid of any content

I am seeking help to understand how to write a custom validator for a reactive form. Here is the component code: private form: FormGroup; ngOnInit() { const this_ = this; this.form = new FormGroup({ 'email': new FormContr ...

Ways to determine the presence of a value in an array

Here is an example array: [ {practitioner: "place_1509136116761", H0709: false, H0911: false, H1113: false, H1315: false}, {practitioner: "place_1509136116772", H0709: true, H0911: false, H1113: true, H1315: false}, {practitioner: "place_15091361166 ...

Missing "this" after initialization? (typescript/node/express)

I am currently working on creating a basic http application using node-express. One issue I encountered is that when setting up routes, the constructor of the MyRouter class has access to this, but it seems to be lost within the getRoutes() function. cla ...

The TypeScript error reads: "An element is implicitly assigned the 'any' type because an expression of type 'any' cannot be used to index a specific type."

[Hey there!][1] Encountering this TypeScript error message: { "Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{ 0: { image: string; title: string; text: string; }; 1: { ...

Choosing From Optional Symbols

Is it feasible to create a custom utility type in TypeScript that resembles the Pick-style, allowing for specified keys that may or may not exist on the selected object type? For example: interface Alpha { a: boolean; b: boolean; } type Selecte ...

Show information retrieved from one API request within another API request

Currently, I am in the process of retrieving data from the Youtube API by utilizing 2 separate requests. One request is used to fetch a list of videos, while the other request provides details for each individual video. The initial request successfully di ...