Creating a dynamic union return type in Typescript based on input parameters

Here is a function that I've been working on:

function findFirstValid(...values: any) {
    for (let value of values) {
        if (!!value) {
            return value;
        }
    }
    return undefined;
}

This function aims to retrieve the first non-undefined value from the list of arguments passed to it.

However, I encountered an issue when trying to add types to it. I wanted the function to have a dynamic union type based on the argument types supplied to it.

For example:

const item1: string = "Welcome!";
const item2: number;
const item3: boolean = true;

// The expected return type should be: string | number | boolean | undefined
findFirstValid(item1, item2, item3);

I attempted to implement this feature:

function findFirstValid<T extends any>(...values: T[]): T | undefined {
    for (let value of values) {
        if (!!value) {
            return value;
        }
    }
    return undefined;
}

Unfortunately, this approach restricts the function to only accept arguments of the same type.

const item1: string = "Welcome!";
const item2: number;
const item3: boolean = true;

// This will result in an error since item2 and item3 are not strings
findFirstValid(item1, item2);

Is there a way to achieve the desired behavior without restricting the function to a single type?

Answer №1

To achieve the desired outcome, you can convert your generic into an array itself. This will allow for different items within the array. Then, you can index the array generic by using number to obtain a union of the types of the values in the array and combine that with a union to include undefined. This approach should give you the expected behavior.

function getFirstDefined<T extends unknown[]>(...values: T): T[number] | undefined {
    for (let value of values) {
        if (!!value) {
            return value;
        }
    }
    return undefined;
}

const foo = getFirstDefined("hey", 2, 5); // string | number | undefined
const asdf = getFirstDefined(5, "hey"); // string | number | undefined
const asdf2 = getFirstDefined(); // undefined

TypeScript Playground 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

Exploring TypeScript: Determining the data type of an object key within the object

Apologies for the vague title, I'm struggling to articulate my problem which is probably why I can't find a solution! Let me illustrate my issue with a snippet of code: type Type<T> = { key: keyof T, doStuff: (value: T[typeof key]) =& ...

Limitations of MaterialUI Slider

Looking for a solution to distribute 350 points across 8 sliders, each with a range of 0-100 and 5 marks at 0, 25, 50, 75, and 100. With each step consuming or returning 25 points, the challenge lies in allowing users to adjust the points allocation withou ...

A guide on how to follow a specific item in an Angular 2 store

I have integrated ngrx store into my Angular2 application. The store reducer contains two objects as shown below: export function loadSuccessNamesAction(state: StoreData, action: loadSuccessNamesAction): StoreData { const namesDataState = Object.assi ...

What are the steps to executing a function that instantiates an object?

Here is an object with filter values: const filters = ref<filterType>({ date: { value: '', }, user: { value: '', }, userId: { value: '', }, ... There is a data sending function that takes an obje ...

Unable to call a component's method from a different component in Angular 7

How can I call the toggleSidebar() method of the SidebarComponent from the HeaderComponent using the callToggleSidebarOnToggleSidebarBtn() method? I am encountering an error that I cannot comprehend. What is the correct way to use a method of one component ...

Is there a way to implement jquery (or other external libraries) within Typescript?

Currently, I am diving into Typescript to enhance my skills and knowledge. For a project that is being served with Flask and edited in VSCode, I am looking to convert the existing JavaScript code to Typescript. The main reason for this switch is to leverag ...

The error "date.isUtc is not a function" is being thrown by MomentAdapter.js

When setting an initial date value for the MUI DatePicker, I encountered the following error: value.isUTC is not a function ./node_modules/@mui/x-date-pickers/AdapterMoment/AdapterMoment.js/AdapterMoment/this.getTimezone@ The date being passed is: 2024-0 ...

An Angular module downloaded from npm seems to be lacking the required @NgModule declaration

There seems to be a missing @NgModule and @Directive declarations in an NPM module, even though they exist in the source code on Github. This is causing an issue with importing a directive for databinding from an HTML attribute. I am attempting to utilize ...

Exploring the process of navigating between pages in Next.js using react-router-dom

Whenever a successful login occurs, I want to redirect the user to a different page. However, I am encountering an error message: https://i.sstatic.net/Wi8XW.png This is the snippet of code that is causing the issue: export default function SignUp() { ...

ConfirmUsername is immutable | TypeScript paired with Jest and Enzyme

Currently, I am experimenting with Jest and Enzyme on my React-TS project to test a small utility function. While working on a JS file within the project, I encountered the following error: "validateUsername" is read-only. Here is the code for the utilit ...

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 ...

The challenges of type verification in Redux reducer

I'm currently facing two specific challenges with Typescript and the Redux reducer. Reducer: const defaultState = { selectedLocation: { id: 0, name: 'No Location' }, allLocations: [{ id: 0, name: 'No Location' }], sele ...

HTMLElement addition assignment failing due to whitespace issues

My current challenge involves adding letters to a HTMLElement one by one, but I'm noticing that whitespace disappears in the process. Here's an example: let s = "f o o b a r"; let e = document.createElement('span'); for (let i ...

Associate a unique identifier string with a randomly generated integer identifier by Agora

For my current web project, I am utilizing a String username as the UID to connect to the channel in an Agora video call. However, I now need to incorporate individual cloud recording by Agora into the project. The challenge lies in the fact that cloud r ...

Angular 4/5 | Custom Dropdown Component

I have been working on a custom dropdown directive in Angular that I can attach to any DOM element. Below is the code for my directive: import { Directive, HostListener } from '@angular/core'; @Directive({ selector: '[appDropdown]' ...

Determining the type of index to use for an interface

Imagine having an interface called Animal, with some general properties, and then either be a cat or a dog with corresponding properties. interface Dog { dog: { sound: string; } } interface Cat { cat: { lives: number; } } type CatOrDog = Cat | D ...

Sending a Thunk to the store using Typescript

Within my primary store.ts file, the following code is present: const store = createStore( rootReducer, composeWithDevTools(applyMiddleware(thunk)) ); store.dispatch(fetchUser()); Upon initial rendering, an action is dispatched to fetchUser in ord ...

Obtaining the host name in server-side rendering (

In the process of developing an app that consists of a client and an API hosted on different domains, the setup resembles the following: [Local] localhost:5000 (client) localhost:5001 (API) [Web] app.domain.com (client) api.domain.com (API) When mak ...

What is the process for importing the TokenExpiredError that is thrown by the verify function in jsonwebtoken?

Is there a way to determine if an Error object thrown by the jwt.verify function in the jsonwebtoken library is of type TokenExpiredError using Typescript's instanceof? For example: import jwt from "jsonwebtoken"; function someFunction() { try { ...

Exploring Dependency Injection in Angular2: A Comparison of TypeScript Syntax and @Inject Approach

I'm currently working with Angular2 build 2.0.0-alpha.34 and I can't figure out why I'm getting different results from these two code snippets. The only variation is between using @Inject(TitleService) titleService and titleService: TitleSe ...