determine function output based on input type

Here's a question that is somewhat similar to TypeScript function return type based on input parameter, but with a twist involving promises. The scenario is as follows: if the input is a string, then the method returns a PlaylistEntity, otherwise it returns an array of PlaylistEntity objects.

type TypeName = string | string[]
type ObjectType<T> = Promise<T extends string ? PlaylistEntity : PlaylistEntity[]>
    async get<T extends TypeName>(playlists: T): ObjectType<T>{
        try {
            const col = collection(firestore, 'playlists')
            if(Array.isArray(playlists)){
                const fetchArray = playlists.slice(0, 10)
                const q = query(col, where('__name__', 'in', fetchArray))
                const docs = await getDocs(q)
                return docs.docs.map(v => {return {id: v.id, ...v.data()} as PlaylistEntity})
            }
            else{
                const docRef = await getDoc(doc(col, playlists))
                return {id: docRef.id, ...docRef.data()} as PlaylistEntity
            }
        }catch (e) {
            throw new HttpException(e.message, HttpStatus.INTERNAL_SERVER_ERROR)
        }
    }

An error message TS2322 pops up saying: "Type 'PlaylistEntity' is not assignable to type 'T extends string ? PlaylistEntity : PlaylistEntity[]'."

This happens at line 43 where we have: return {id: docRef.id, ...docRef.data()} as PlaylistEntity

Answer №1

Consider using function overloads to improve the modeling of your TS types.

// Define a dummy interface.
interface PlaylistEntity {
    id: string
};

// Function that resolves to an array of PlaylistEntity when passed a string[].
async function getPlaylistEntries(playlists: string[]): Promise<PlaylistEntity[]>;

// Function that resolves to a single PlaylistEntity when passed a string.
async function getPlaylistEntries(playlists: string): Promise<PlaylistEntity>;

// Implement both overloads with a single function.
async function getPlaylistEntries(playlists: string | string[]) {
    try {
        if (Array.isArray(playlists)){
            return playlists.map((p: string) => ({id: "some-id"}));
        }
        else{
            return {id: "some-id"};
        }
    }catch (e) {
        throw new Error();
    }
}

// Type inference for onePlaylistEntry is Promise<PlaylistEntity>
const onePlaylistEntry = getPlaylistEntries("a")

// Type inference for arrOfPlayListEntries is Promise<PlaylistEntity[]>
const arrOfPlayListEntries = getPlaylistEntries(["a"])

Test it out on the TS 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

Tips for modifying the language of an Angular Application's OneTrust Cookie Banner

I'm currently developing an Angular application and utilizing OneTrust for managing cookie consent. The issue I'm encountering is that while the rest of the components on the login page are properly translated into the target language, the OneTru ...

Can you specify the third argument sent to the listener?

Recently I delved into exploring the capabilities of the d3 framework. One thing that caught my attention was the presence of a third parameter in the event listener for v3. Despite always being 0, I couldn't find any explanation on its intended purpo ...

increasing the size of a picture without resorting to a pop-up window

Struggling to implement a product details tab within a table that features a clickable image. When the image is clicked, it should enlarge but the width doesn't adjust accordingly. I'm using bootstrap 5.3 and can't seem to identify the root ...

Unable to load nested iframe

When working with an HTML document, I tried to add an iframe in the body without any cross-origin restrictions (same URL). However, when I tried to do the same thing within the appended iframe, although the nested iframe element was successfully added to ...

I possess a primary menu with several submenus, yet I am encountering difficulty accessing the submenus. My goal is to efficiently navigate and access the appropriate submenu within the main menu

I am facing an issue with my CSS where the sub menu is currently showing from the left side, but I would like it to slide up and down instead. .outer { width: 100%; text-align: center; background-color: Gray; padding-top: 20px; bord ...

What is the best way to extract value from a JSON object with jQuery?

How can I retrieve the value of 'FRI' from the JSON feed returned by an AJAX call using jQuery? $.ajax({ url: query, type: "GET", dataType: "json" success: function(data) { var day = // extract data value from JSON ...

Implementing model synchronization on server initialization with Next.js and sequelize

When it comes to using Express with React on the backend, I'm accustomed to working in a server.js file to synchronize the database. However, I've recently started working with Next.js and noticed that there's no server.js file to sync the m ...

If the width of the table is set to 100% in the CSS, the legend in the Flot chart will automatically shift to the

When the CSS for the table is set to { width:100%}, the Flot chart's legend moves to the left side. Is there any way to maintain the table { width:100%} while also preventing this shift, considering that the CSS is applied site-wide? Here is a jsfid ...

Having trouble with sending information to the PHP server, unable to determine the root cause

Can someone help me figure out why the data from a form being sent to a php script for sending an email isn't working correctly? It's part of a template code but I suspect there might be an error. Specifically, I believe the {'userName' ...

Building a BaseObserver in TypeScript with RxJS

Initially, I created a class called BaseObserver in Swift. In the subscribe method, I pass this class. Now, I am attempting to achieve the same functionality in RxJS using TypeScript. This approach proves useful when you need to execute actions both befor ...

Send in unaltered input information

Recently, I encountered an issue with a software feature that allows users to partially edit their existing information. It seems that only the edited part gets submitted correctly, while the unedited sections end up empty. I suspect the problem arises fro ...

Unlocking the res property in index.js from an HTML script tag: A step-by-step guide

Can anyone help me with the access variable issue I am facing? I have two files, index.js and page.ejs. These files require me to create a timer linked with datetimes stored on my local server. //index.js.. router.get('/mieiNoleggi', functio ...

What is the best way to update only a portion of a nested schema in mongoose?

UPDATE: Through numerous trials, I finally discovered a successful method that converts any object into a format that mongoose can interpret. Take a look at the solution provided here: const updateNestedObjectParser = (nestedUpdateObject) => { cons ...

Creating multiple divs with input fields dynamically using JavaScript is a useful skill to have

I need to generate 3 input text boxes for gathering user input on names and email addresses. These inputs must be created dynamically, meaning that as the user clicks on the email input field, a new line with all three elements should be generated. Below i ...

Dealing with query strings within routeprovider or exploring alternative solutions

Dealing with query strings such as (index.php?comment=hello) in routeprovider configuration in angularjs can be achieved by following the example below: Example: angular.module('app', ['ngRoute']) .config(function($routeProvider, $loc ...

Targeting lightgallery.js on dynamically added elements in Javascript: The solution to dynamically add elements to

I am facing a challenge in targeting dynamically added elements to make them work with lightgallery.js. Take a look at the example below: <div id="animated-thumbs" class="page-divs-middle"> <!-- STATIC EXAMPLE --> ...

What is the best method to access an element with Vue.js?

I currently have a form set up like this <form v-on:submit.prevent="save_data(this)"></form> and a method defined in Vue.js like this methods: { save_data: function(f){ } } In jQuery, we can access the form using $(f)[0] My question ...

Angular code is failing to send a signal to the server following a $http.post request

I've been using angular for about a week now and I've been struggling to solve this issue. I have a service that wraps around $http because multiple controllers make calls to the same URL. On one particular page, there is a lot of server-side bus ...

Leveraging moment.format Function in Angular within an HTML Context

Is there a way to implement the moment.format method in HTML? Currently, I am utilizing the toLocaleDateString method to showcase an array of dates: <ng-template let-event> <div>{{event.date.toLocaleDateString(' ...

Angular Lifecycle Hook - Data loading initializes after the view initialization is complete

In my component, I have loaded a firestore document and converted it into a plain js object within the constructor. However, when trying to access the field values in the template, there is a slight delay in loading them. This results in an error being dis ...