Is there a way to make a parameter optional instead of mandatory?

Interactive Editor

My goal is to create a function where undefined values are optional, while non-optional values remain required. Here is an example:

type TypeObj = {
  a: undefined;
  b: number;
  c: string;
}

call("a"); call("b", 1); call("c", "3"); // should work
call("b", "a"); call("c", 3) // shouldn't work
call("b"); call("c") // also shouldn't work

However, my current implementation allows calling the function on 'b' and 'c' without providing the second parameter, which is not desired.

function call<K extends keyof TypeObj = keyof TypeObj>(key: K, param?: TypeObj[K]) {

}

call("a"); call("b", 1); call("c", "3"); // works as expected
call("b", "a"); call("c", 3) // does not work correctly
call("b"); call("c") // works incorrectly (should be fixed)

Answer №1

To achieve this specific functionality, it is essential for call() to support multiple call signatures. Traditionally, you would have to turn call() into an overloaded function, but another approach involves accepting a tuple-typed rest parameter.

Here's one way to implement it:

type OptionalIfUndefined<T> =
  undefined extends T ? [param?: T] : [param: T];

function call<K extends keyof TypeObj>(
  key: K, ...[param]: OptionalIfUndefined<TypeObj[K]>
) {
  const _param = param as TypeObj[K]; // <-- might need this
}

The type OptionalIfUndefined<T> is a conditional type that determines if undefined can be assigned to T. Depending on the result, it either creates a tuple with an optional element of type T, or a tuple with a required element of type T.

In the function definition of call(), we use the rest parameter type

OptionalIfUndefined<TypeObj[K]>
. By employing destructuring assignment, we extract the single element from the array since only its value is needed.

If you expect param to be recognized as type

TypeObj[K]</code within the implementation of <code>call()
, you may face challenges due to the generic conditional type being opaque to the compiler. It’s recommended to assert the type like so:
const _param = param as TypeObj[K]
, and then utilize _param instead of
param</code if necessary.</p>
<p>Let’s test it out:</p>
<pre><code>call("a") // correct
call("a", undefined) // correct
call("b", 1); // correct
call("b") // error
call("c", "a"); // correct
call("c") // error

Everything seems to be functioning as expected!

Access the code on the TypeScript 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

Compiling Vue with TypeScript: Troubleshooting common errors

Using Vue Components with Templates Multiple Times in TypeScript I am working on utilizing a component with a template multiple times within another component. The code is split between a .html file and a .ts file. The .html file structure is as follows: ...

Error in TypeScript: Unable to assign type 'string' to type 'number | ""'

I am new to TypeScript and struggling to comprehend the error message below. Type '{ order: string; }[]' is not compatible with type 'TestType[]'. Type '{ order: string; }' is not assignable to type 'TestType'. ...

The 'innerHTML' property is not present in the 'EventTarget' type

Currently, I am working with React and Typescript. My goal is to store an address in the localStorage whenever a user clicks on any of the available addresses displayed as text within p elements. <div className="lookup-result-container& ...

Error encountered in Angular 2 with RXJS Observable: Unable to call function catch() on this.http.get(...).map(...) due to TypeError

Everything was running smoothly with my Service until today, when I encountered the following error: TypeError: this.http.get(...).map(...).catch is not a function. Upon debugging the code, it crashes at the catch method. import { Test } from "./home.c ...

Since updating from Angular 16 to 17, I am experiencing a TypeScript compilation issue specifically related to 'openui5'

Everything was running smoothly in Angular16. I had "@types/openui5" : "1.40.4" listed in my dev-dependencies. Here is how it's configured in the tsconfig.json: { "compilerOptions": { "downlevelIteration": ...

Tips for incorporating a fresh variant into the default typography of MUI using TypeScript

While following the official MUI instructions here, a question arose. To customize the primary color in the file newTheme.ts and add a new variant type post: import { createTheme } from "@mui/material"; const newTheme = createTheme({ palette ...

Find the length of time in Typescript (measured in hours, minutes, and seconds)

Trying to calculate the duration between two dates in TypeScript (Angular): 2021-11-19 21:59:59 and 2021-11-19 22:00:18 let startDate: Date = new Date(start); let endDate: Date = new Date(end); if(end != null) { let duration = new Date(endDate.getT ...

Managing state in React using useEffect and useState - Avoiding undefined values

Encountering the same undefined error in various components. After verifying that the data is coming from the API, not blocked by CORS, and accessible in the useEffect callback, it appears that the issue lies in setting the state. I attempted to replace th ...

A guide on leveraging *ngFor in Angular 4 to assemble a table featuring 2 columns in every row

I have an array of objects as shown below let columns = [ {id: 1, columnName: 'Column 1'}, {id: 2, columnName: 'Column 2'}, {id: 3, columnName: 'Column 3'}, {id: 4, columnName: 'Column 4'} ]; My ...

Screen a roster for shared elements with another roster

Within my dataset, I am working with a List of Objects that adhere to the following Model structure: export class Animal{ public aniId: number; public aniName: string; } export Class Zoo{ public id: number; public name:string; public aniId: number ...

Struggling with slow TypeScript compilation?

My current setup involves TypeScript 2.2.1, but I've been facing prolonged compilation times when running tsc. In an attempt to gather more information, I decided to utilize the --diagnostics option. However, I soon discovered that the "Total time" di ...

Using TypeScript with React Redux, encountering issue of property not being available in the Reducer from the ActionType

Currently, I am learning how to implement a Reducer in Redux while using React with TypeScript. I have encountered an issue that I need help with. Below are the action types that I am working with: import { LoginResponseInterface } from "../../interfaces ...

How can you incorporate TypeScript's dictionary type within a Mongoose schema?

When using TypeScript, the dictionary type format is: { [key: string]: string; } However, when I try to define a custom schema in mongoose, it doesn't work as expected. const users = new Schema({ [key: string]: String, }); I also attempted t ...

What interface should be utilized for an element containing the method "GetWrappedInstance"?

Currently, I am working on a project using React and Redux in combination with typescript. In this project, I have encountered an issue where I need to access the reference of a wrapped instance using this.refs.items.getWrappedInstance(). However, when att ...

The Children Element in Next.js and React Context with TypeScript is lacking certain properties

Encountering a mysterious error while trying to implement React's Context API in Next.js with TypeScript. The issue seems to be revolving around wrapping the context provider around the _app.tsx file. Even though I am passing values to the Context Pr ...

Utilizing Typescript for directive implementation with isolated scope function bindings

I am currently developing a web application using AngularJS and TypeScript for the first time. The challenge I am facing involves a directive that is supposed to trigger a function passed through its isolate scope. In my application, I have a controller r ...

What is the best way to transfer user data from the backend to the frontend?

I successfully created a replica of YelpCamp using Node and EJS, but now I am attempting to convert it into a Node-React project. Everything was going smoothly until I encountered an issue while trying to list a specific user in the SHOW route. In order to ...

Can a generic type be utilized to instantiate an object?

In my code, I have a class named Entity as shown below: class Entity { constructor(readonly someValue: string) {} someFunction() {} } Now, I am trying to create a class that will handle these entities and be able to create instances of them. In or ...

Setting up "connect-redis" in a TypeScript environment is a straightforward process

Currently, I am diving into the Fullstack React GraphQL TypeScript Tutorial I encountered an issue while trying to connect Redis with express-session... import connectRedis from "connect-redis"; import session from "express-session"; ...

Error: Missing provider for MatBottomSheetRef

While experimenting in this StackBlitz, I encountered the following error message (even though the MatBottomSheetModule is imported): ERROR Error: StaticInjectorError(AppModule)[CountryCodeSelectComponent -> MatBottomSheetRef]: S ...