Exploring the versatility of functions through annotations

Hello community! Seeking assistance for annotating a polymorphic function. I have multiple types that share a common key "type" along with other keys:

type T1 = { type: 't1', someKey: number };
type T2 = { type: 't2', anotheKey: string };
type T3 = { type: 't3', andAnotherKey: boolean };
type T = T1 | T2 | T3;

I also have a map of functions. Each key in this map corresponds to the "type" field, and the value is a function taking an argument of the respective type:

const TYPE_FN_MAP = {
  t1: (argT1: T1) => argT1.someKey,
  t2: (argT2: T2) => argT2.anotheKey,
  t3: (argT3: T3) => argT3.andAnotherKey,
} as const

How do I annotate the polymorphic function:

const polymorphicFn = (argT) => TYPE_FN_MAP[argT.type](argT);

The idea is that when adding a new type, simply extend the TYPE_FN_MAP with a function taking an argument of that type, while keeping the polymorphicFn function unchanged. If the "type" field is forgotten in a new type, TypeScript will flag an error in the polymorphicFn function.

Playground

Answer №1

Are you in search of something similar to this?

type ARG_TYPE = typeof TYPE_FN_MAP;

function customTest<K extends keyof ARG_TYPE>(event: K, ...arg: Parameters<ARG_TYPE[K]>) : ReturnType<ARG_TYPE[K]> {
  // Implement logic here
  return {} as unknown as ReturnType<ARG_TYPE[K]>;
}

customTest('test1', { type: 'test1', someValue: 10 })

Link

If a valid parameter is not provided for the first parameter, an error may occur like this:

customTest('test1', { someValue: 10 })
// Error: Argument of type '{ someValue: number; }' is not assignable to parameter of type 'Test1'.
  Property 'type' is missing in '{ someValue: number; }' but required in 'Test1'.(2345)

However, duplication may occur if the key 'type' is provided both within the specified type and in TYPE_FN_MAP.

A simpler approach could be:

type TYPE_FN_MAP = {
  test1: () => { someValue: number },
  test2: (param: boolean) => { anotherValue: string },
  test3: () => { andAnotherValue: boolean },
} 

function simplifiedTest<K extends keyof TYPE_FN_MAP>(event: K, ...arg: Parameters<TYPE_FN_MAP[K]>) : ReturnType<TYPE_FN_MAP[K]> {
  // Perform operation here
  return {} as unknown as ReturnType<TYPE_FN_MAP[K]>;
}

const result = simplifiedTest('test1');
console.log(result.someValue)

simplifiedTest('test2') // Expected 2 arguments, but received only 1.(2554)
simplifiedTest('test2', true)

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

Taking a segmented snapshot of a canvas using a flexible design scheme

I am working with a canvas that contains multiple div elements representing different sections of the canvas. However, when I capture these sections, they do not appear exactly as displayed on the screen. How can I track and accurately capture the div area ...

Node.js and mongoose provide a powerful tool for filtering documents dynamically by leveraging a variable that is dependent on another document. Want to learn

I've hit a bit of a roadblock here... I'm trying to add a new property to a document that will change based on the values in that document as well as another document. Let me provide an example to clarify. First, I have a Candidate Schema: const ...

Is it feasible to mock a defined function in Typescript for a unit test scenario?

Currently, I am working on typescript code that compiles into javascript, gets bundled with rollup, and is utilized by a framework. This framework exposes a library to me in the global scope, taking the form of a function: fun({ prop1: number, ...

What is the best way to integrate ag-grid with Observable in Angular 2?

After conducting extensive research on the Internet, I am still struggling to connect the pieces. My angular2 application utilizes an Observable data source from HTTP and I am attempting to integrate ag-grid. However, all I see is a loading screen instead ...

Basic exam but located in a place that is not valid

Here is a test I am working on: // import {by, element, browser} from "protractor"; describe('intro', () => { beforeEach(() => { browser.get(''); }); it('should have multiple pages', () => { let buttonOn ...

The Standalone Component does not appear for debugging in webpack:source when utilizing an incompatible version of Node

I have developed two components: https://i.sstatic.net/fSNqa.png However, after running ng serve, I am only able to see one component in the source of the Chrome browser: https://i.sstatic.net/VzdDS.png How can I troubleshoot this standalone component? ...

The FormGroup is experiencing issues with the functionality of the Submit button

I've been working on creating a FormGroup, but I've encountered an issue with the submit button not functioning as expected. The component in question is named create. Any idea what could be causing this problem? create.component.html ...

De-generify the interface

Is it possible to eliminate generics from an interface? Sample code: This is what I currently have: interface ServerMessages { [ActionType.EVENT_1]: ResponseEventBody1; [ActionType.EVENT_2]: ResponseEventBody2; [ActionType.EVENT_3]: ResultModifier ...

TypeScript does not automatically deduce types

Here is a function I am working with: type DefaultEntity = { id: string; createdBy: string; [fieldName: string]: unknown; }; abstract find<T, Schema extends string | (new () => T)>( schema: Schema, id: string, ): Promise<(Schema ...

Leveraging non-ionic-native Cordova plugin

I'm currently working on integrating the [This]https://github.com/louisbl/cordova-plugin-locationservices plugin into my Ionic 4 app. Since it's a non-Ionic-native plugin, what is the proper way to call its functions within my TypeScript code? ...

Guide to sending a generic to a React component and leveraging its power within the component

I am currently working on developing an input component that requires a displayName as a string and a value as a generic type. Additionally, it needs to take a function as a prop that will be triggered to handle the value when the input changes. For examp ...

When incorporating a new group in a three.js Scene, the older object groups are automatically eliminated

Currently, I am developing a visual components designer that includes a functionality to group objects together under a specific name. When any of the grouped objects is selected, a red box should be displayed around them. However, I am facing an issue wh ...

What is the best way to add all the items from an array to a div element?

I am currently facing an issue where only the last object in my array is being added to my div using the code below. How can I modify it to add all objects from the array to my div? ajaxHelper.processRequest((response: Array<Vehicle.Vehicle>) ...

Ways to create a method that can be overridden

Is there a way to declare a virtual method in TypeScript? I'm attempting to achieve something similar to the following: export abstract class SuperClass { public virtual enable(enableComponents: boolean): void { } } ...

Guide to Generating a Compilation Error with Method Decorators in Typescript

Currently, I am developing a library named expresskit which allows the use of decorators to define routes, params, and other functionalities for express. While refactoring the codebase, I am considering implementing restrictions on the types of responses a ...

Unexpected character error occurs when using VSCode with Vue: ''‌'

Recently, I've encountered some strange errors while working on a Vuejs project in VSCode. Whenever I try to write arrow functions or use brackets, I get unexpected character errors. For example, if I insert an empty computed section between methods a ...

Tips for utilizing generic object utilities for objects defined by interfaces in Typescript

I am facing an issue with my code where I have defined an object with an interface and a utility function to clean up the object by removing undefined properties. However, when I try to pass this object to the utility function, Typescript throws an error. ...

Accessing nested objects within an array using lodash in typescript

After analyzing the structure of my data, I found it to be in this format: {property: ["a","b"], value : "somevalue" , comparison : "somecomparison"} I am looking for a way to transform it into a nested object like so: { "properties": { "a": { ...

Are there any methods to incorporate Facebook and Google login into an Ionic progressive web app (PWA)?

After successfully developing an app in Ionic 3 for Android and iOS, I encountered a problem when adding the browser platform. The Facebook and Google login features were not functioning as expected. Despite the assurance from Ionic documentation that the ...

Guide to exporting (and using) JSDoc annotations in TypeScript NPM packages

Looking to enhance my skills in creating npm packages with TypeScript. I have a small project available at https://www.npmjs.com/package/lynda-copy-course/, and so far, the project structure is successful in: being executable from the command line after ...