Tips for restricting the signature within a function depending on the argument's value

Trying to consolidate interface methods into a single function with an additional operation parameter. The function can be called as expected, but struggling to narrow the signature within the function. Found some assistance in this SO post, but still encountering issues with args[1] being considered as possibly undefined in the "plus" case:

interface Calculator {
    plus: (a: number, b: number) => number;
    unaryPlus: (a: number) => number;
}

type CalculateParameters = {
    [P in keyof Calculator]: [P, ...Parameters<Calculator[P]>];
}[keyof Calculator];

const calculate = (...[operation, ...args]: CalculateParameters) => {
    switch (operation) {
        case "plus":
            // Object is possibly undefined
            return args[0] + args[1];
        case "unaryPlus":
            return args[0];
        default:
            throw new Error("Unknown operation.");
    }
};

// Working as expected
export const x = calculate("plus", 1, 2);
export const y = calculate("unaryPlus", 1);

Playground

Attempted conditional types as recommended here, but required a lot of duplication and casting. Is it feasible to narrow the signature within calculate without these methods?

P.S. Once the argument typing issue is resolved, now dealing with accurately typing the return value. Calculator may have functions that return types other than number, and calculate should be able to accommodate that.

Answer №1

If you're looking for a solution, consider the following:

interface Calculator {
    sum: (num1: number, num2: number) => number;
    unarySum: (num: number) => number;
}

type CalculateParams = {
    [P in keyof Calculator]: [P, ...Parameters<Calculator[P]>];
}[keyof Calculator];

const calculate = (...args: CalculateParams) => {
    switch (args[0]) {
        case "sum":
            // Potential object undefined error
            return args[1] + args[2];
        case "unarySum":
            return args[1];
        default:
            throw new Error("Unknown operation.");
    }
};

// Will perform as anticipated
export const a = calculate("sum", 3, 5);
export const b = calculate("unarySum", 7);

For further insights, visit How to infer/narrow-down a function parameter type based on the narrowed-down type of another function parameter?

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 process for configuring NextJS to recognize and handle multiple dynamic routes?

Utilizing NextJS for dynamic page creation, I have a file called [video].tsx This file generates dynamic pages with the following code: const Video = (props) => { const router = useRouter() const { video } = router.query const videoData = GeneralVi ...

Using TypeScript to assign values to object properties

In myInterfaces.ts, I have defined a class that I want to export: export class SettingsObj{ lang : string; size : number; } Now I need to reference this class in another file named myConfig.ts in order to type a property value for an object called CO ...

What is the best way to create an interactive experience with MapLibre GL in Full Screen mode?

Hello, I am seeking a solution to create a map with the interactive option set to false, but once in full screen mode, I need this parameter to be true. Do you have any suggestions or ideas on how to achieve this? const _map = new MapGL({ contai ...

Leveraging Component without the need for Import

Is it possible to use a component without re-importing it if it's already declared in AppModule? With 10 or more pages/components to manage, importing each one can be challenging. Here is my app.module.ts import { NgModule, ErrorHandler } from &apos ...

How do I disable split panel on Ionic 2 login page exclusively?

I have successfully implemented the split-pane feature in my app.html file. However, I am facing an issue where the split pane is being applied to every page such as login and SignUp. Can someone please guide me on how to restrict the split pane function ...

Terminating a function during execution in JavaScript/TypeScript

Currently, I am in the process of developing a VSCODE extension using TypeScript. Within this extension, there is a particularly large function that is frequently called, but only the final call holds significance. As a solution, I am attempting to elimina ...

The culprit behind Angular 11 app error: Unidentified router outlet triggering 'No routes match' issue

In my Angular 11 application, I am utilizing a named router-outlet. The setup in my app.component.html file looks like this: <ng-container *ngIf="showGeneric"> <router-outlet name="general"> </router-o ...

The Figma plugin that was generated does not come with TypeScript typings included

As I attempt to follow the plugin setup guide located here, my plugin is quite simple yet effective. It consists of the following code: figma.showUI(__html__); // @ts-ignore console.log(figma.currentPage.selection[0].cornerRadius); When executed as is, t ...

I keep getting the error message "Element is missing a 'key' prop", even though I have already included a key in my loop. What could be the issue here?

Every <td> and <tr> in my code has a unique key assigned to it. Check out the complete code of my component below: export default function TableComponent( data: any ) { const columnNames = Object.keys(data.data); const rowIndices = Obj ...

Creating a Build-Free Workflow in a TypeScript Monorepo

Imagine having this monorepo structure: /apps /apps/app1 /apps/app1/src (includes index.ts and various other files and subdirectories) /apps/app1/tsconfig.json /apps/app1/package.json /apps/app2 /apps/app2/src (contains index.ts and many other files an ...

Struggling to display blob URL on "pdf-viewer" component with "ng2-pdf-viewer" in Angular version 10

I am facing an issue with an API that returns uploaded files as blobs. When trying to bind the src with a blob URL, nothing is shown. However, if I bind it with a direct URL, the PDF file is displayed successfully. Below is my code snippet. My TypeScript ...

Issue with Ionic 4 IOS deeplinks: Instead of opening in the app, they redirect to the browser

After working diligently to establish deeplinks for my Ionic 4 iOS application, I meticulously followed a series of steps to achieve this goal: I uploaded an Apple site association file to the web version of the app, ensuring the utilization of the prec ...

Using event.target to pass HTML form data to FormData is causing an error stating that the Argument of type 'EventTarget' cannot be assigned to a parameter of type 'HTMLFormElement'

Looking to extract data from a form and store it in FormData: const handleSubmit = (e: FormEvent<HTMLFormElement>) => { e.preventDefault(); const formData = new FormData(e.target as HTMLFormElement); const value = formData.get(' ...

Error message: The database query function is encountering an issue where the property 'relation.referencedTable' is undefined and cannot be accessed

Currently, I am working with two schemas named products.ts and category.ts. The relationship between these files is defined as one-to-many. In the products.ts file: import { pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; import ...

Ionic3 footer using ion-tabs

Is there a way to create a common footer for all pages with 5 buttons, where the first button is selected by default? The page opened by this first button should have three tabs. I have already created the tabs but am unsure how to add the footer without r ...

What is the best way to test chained function calls using sinon?

Here is the code I am currently testing: obj.getTimeSent().getTime(); In this snippet, obj.getTimeSent() returns a Date object, followed by calling the getTime() method on that Date. My attempt to stub this functionality looked like this: const timeStu ...

Issue with Angular Reactive form: Checkbox checked property not binding correctly when the page initially loads

Looking to achieve Two-way data binding of Checkbox in Angular Reactive forms. After checking the checkbox, I am updating the 'isdateChkd' variable and storing it in the state. Despite the variable being set to TRUE, the checkbox does not get aut ...

Exploring PrimeNG's method for expanding and collapsing groups

I'm attempting to incorporate two buttons that can be used to either expand or collapse all the groups in my code utilizing primeNG. Below is the functioning code: PLUNKER <p-dataTable [value]="data" sortField="room" rowGroupMode="subheader" grou ...

Jest: Test fails due to import statement in node_module dependency

Short Version I'm experiencing a crash in my Jest test due to a SyntaxError related to an import statement outside a module. The issue arises from a node_module that uses the import statement. How can I resolve this error? Situation Overview In deve ...

Resolving the Angular NG0100 Error: Troubleshooting the ExpressionChangedAfterItHasBeenCheckedError

I am currently working on implementing a dialog component that takes in data through its constructor and then utilizes a role-based system to determine which parts of the component should be displayed. The component code snippet looks like this: export cl ...