Determine rest parameters based on the initial argument

Struggling to generate a solution that infers the arguments for an ErrorMessage based on the provided code input.

./errorCodes.ts

export enum ErrorCodes {
  ErrorCode1,
  ErrorCode2,
  ErrorCode3
}

./errorMessages.ts

export const ErrorMessages = {
  [ErrorCodes.ErrorCode1]: (a1: string, a2: string) => `${a1} ${a2} message1...`,
  [ErrorCodes.ErrorCode2]: (a1: boolean) => `${a1} message2...`,
  [ErrorCodes.ErrorCode3]: `message3...`
}

./formatMessage.ts

import {ErrorCodes} from "./errorCodes"
import {ErrorMessages} from './errorMessages'


export const formatMessage = (
  code: ErrorCodes,
  ...args: Parameters<typeof ErrorMessages[typeof ErrorCodes[typeof code]]>
) => {
  const message = ErrorMessages[code];
  const errorCode = `[${ErrorCodes[code]}]`;

  switch (typeof message) {
    case "string": {
      return [errorCode, message].join(" ");
    }
    case "function": {
      return [errorCode, message(...args)].join(" ");
    }
  }

Attempting to define the arguments dynamically:

...args: Parameters<typeof ErrorMessages[typeof ErrorCodes[typeof code]]>

Encountering some challenges:

  1. Lack of autocomplete functionality when calling the function.
  2. Adding string returns in ErrorMessages caused type errors.

Answer №1

Let me provide a definition for the function:

export const formatMessage = <E extends ErrorCodes>(
  code: E,
  ...args: typeof ErrorMessages[E] extends infer Fn extends (...args: any) => any 
    ? Parameters<Fn> 
    : [typeof ErrorMessages[E]]
) => {
  const message = ErrorMessages[code];
  const errorCode = `[${ErrorCodes[code]}]`;

  switch (typeof message) {
    case "string": {
      return [errorCode, message].join(" ");
    }
    case "function": {
      return [errorCode, (message as (...args: any) => any)(...args)].join(" ");
    }
  }
}

Now, let's discuss the modifications.

  • The function needs to be generic. Using something like

    typeof ErrorMessages[typeof ErrorCodes[typeof code]]
    

    may not function as intended. typeof code does not refer to the type of code used when calling the function. It only points to its static type, which is ErrorCodes. This statement just creates a union of all cases.

    Instead, we should assign the generic type E to code. The type of E is decided by the caller and can be used in the second parameter type.

  • The second parameter must employ a conditional type to verify if typeof ErrorMessages[E] is a function type before passing it to Parameters. As you noted, the utility type cannot accept a string because it is not a function.

  • The error message

    A spread argument must either have a tuple type or be passed to a rest parameter

    cannot be completely resolved. The compiler does not entirely comprehend the implications of the type of ...args and how it relates to message. Therefore, we need to assert that message is a function that can be called with any arguments.

    return [errorCode, (message as (...args: any) => any)(...args)].join(" "); 
    

With these adjustments, the function can now be invoked like this:

formatMessage(ErrorCodes.ErrorCode1, "a", "b")
formatMessage(ErrorCodes.ErrorCode2, true)
formatMessage(ErrorCodes.ErrorCode3, "a")

Playground

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

Transmit data via XMLHttpRequest in smaller portions or through a ReadableStream to minimize memory consumption when handling large datasets

Recently, I've been experimenting with JS's XMLHttpRequest Class for handling file uploads. Initially, I attempted to upload files using the following code: const file = thisFunctionReturnsAFileObject(); const request = new XMLHttpRequest(); req ...

Having trouble obtaining search parameters in page.tsx with Next.js 13

Currently, I am in the process of developing a Next.js project with the Next 13 page router. I am facing an issue where I need to access the search parameters from the server component. export default async function Home({ params, searchParams, }: { ...

the Sprite fails to appear on the screen

Can you help me figure out how to fix the issue I'm having with loading images in this component? Currently, when I refresh the page, the image does not load properly and appears resized to 1 pixel width. Should I wait for the image to fully load befo ...

Sorting elements in an array based on an 'in' condition in TypeScript

I am currently working with an arrayList that contains employee information such as employeename, grade, and designation. In my view, I have a multiselect component that returns an array of grades like [1,2,3] once we select grade1, grade2, grade3 from the ...

How to pass parameters between pages in Ionic 2 using navParams when the return nav button is clicked

Is there anyone familiar with how to return a simple value (or JSON) by clicking on the return button in Ionic 2's navigation bar? I understand that navParam can be used to send a value when pushing a page, but I am unsure how to implement the same fu ...

What is the best way to integrate Tawk.to into a React application while using typescript?

Having some issues integrating tawk.to into my website built with React and TypeScript. I have installed their official npm package, but encountered an error message: import TawkMessengerReact from '@tawk.to/tawk-messenger-react'; Could not fin ...

Angular production application is experiencing issues due to a missing NPM package import

Objective I am aiming to distribute a TypeScript module augmentation of RxJS as an npm package for usage in Angular projects. Challenge While the package functions correctly in local development mode within an Angular application, it fails to import pro ...

Eliminating an element from an object containing nested arrays

Greetings, I am currently working with an object structured like the following: var obj= { _id: string; name: string; loc: [{ locname: string; locId: string; locadd: [{ st: string; zip: str ...

Trouble with V-if not updating after property is modified within an async TypeScript function

There is a scenario where one HTML element becomes hidden after an async call returns from the server, while another HTML element is displayed: <template> <div v-if="!showElementTwo">Element 1</div> <div v-if="show ...

How to send parameters with the fetch API

After completing a task that involved converting code from Angular HttpClient to using fetch API, I encountered an issue with passing parameters. Below is the original code snippet before my modifications: let activeUrl = new URL(this.serverAddress); ...

Having trouble getting anime.js to function properly in an Ionic 3 project?

I have been attempting to incorporate anime.js into my Ionic 3 project, but I keep encountering an error when using the function anime({}) in the .ts file. Error: Uncaught (in promise): TypeError: __webpack_require__.i(...) is not a function TypeError: _ ...

Automate the process of triggering the "Organize Imports" command on a VSCode / Typescript project through code

Is there a way to automatically run VSCode's 'Organize Imports' quickfix on every file in a project, similar to how tslint can be run programatically over the entire project? tslint --project tsconfig.json --config tslint.json --fix I want ...

Guide on Implementing Link href in Next.js v12

When I set the href as a string, the link functions properly. However, when I use an object for the href, the link fails to work. Despite seeing the correct querystring when hovering over the link, it always takes me back to the first page. // ProdCard t ...

Working with intricately structured objects using TypeScript

Trying to utilize VS Code for assistance when typing an object with predefined types. An example of a dish object could be: { "id": "dish01", "title": "SALMON CRUNCH", "price": 120, ...

Can anyone assist me with creating a custom sorting pipe in Angular 2?

*ngFor="let match of virtual | groupby : 'gameid' I have this code snippet that uses a pipe to group by the 'gameid' field, which consists of numbers like 23342341. Now, I need help sorting this array in ascending order based on the g ...

Accessing properties in Angular/TypeScript: extracting values from a partially extended interface

I am fairly new to Angular/TS and I may not have worded this correctly, but I will do my best to explain. I have defined 2 interfaces where one extends the other as shown below: export interface CustomerModel { firstName: string; lastName: string; ...

Tips for resolving the issue when Chrome is able to load the page but Postman cannot find it

I'm encountering a perplexing situation that is entirely new to me and difficult to comprehend. I find myself unable to decipher what exactly I am witnessing, leading to uncertainty about why it is occurring, not to mention the challenge of determinin ...

Error Message: Angular NullInjectorException - The provider for "[Object]" is not found

While developing a simple Flashcard application that performs CRUD operations using Angular, Node.js, Express, and PostgreSQL, I encountered the following error: flashcards-area.component.ts:24 ERROR NullInjectorError: R3InjectorError(AppModule)[Flashcard ...

Error encountered: Uncaught SyntaxError - An unexpected token '<' was found while matching all routes within the Next.js middleware

I am implementing a code in the middleware.ts file to redirect users to specific pages based on their role. Here is the code snippet: import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' import { get ...

organizing strings in alphabetical order using TypeScript

My md-collection is set up to display a list of emails like this: <md-collection-item repeat.for="u of user" class="accent-text"> <div class="row"> <di ...