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

Web pages that dynamically update without the need for reloading

Recently, I stumbled upon slack.com and was immediately captivated by its user interface. For those unfamiliar with it, navigating the site is quite simple: There's a sidebar on the left and a main content area on the right. When you click on an item ...

Transforming button hues and passing a property to a subcomponent when clicked using vue.js

Just starting out with vue.js, I am attempting to create a component that functions in the following way: I have four buttons and when I click on one button, I want to change the colors of all four buttons and send a prop to a child component indicating w ...

parsing a TypeScript query

Is there a simpler way to convert a query string into an object while preserving the respective data types? Let me provide some context: I utilize a table from an external service that generates filters as I add them. The challenge arises when I need to en ...

Mastering advanced String templating using loops and control statements in Javascript

During runtime, I receive an array similar to the example below: var colors = ['red', 'green', 'blue']; I then need to create a JSON String that looks like this: { "color" : { "name" : "foo", "properties ...

I aim to generate a JavaScript string that, when placed within a div tag, will display as a list

I need assistance with formatting a string that contains a list of items to display in a specific way within a div tag using JavaScript. The string has multiple items that I wish to show as a bulleted list. Here is an example of the string: const items = & ...

Vue event manager, accessible for all components

I have created a new Vue instance and assigned it to the window object, thinking that it would be accessible throughout all components. I expected this setup to allow me access to events emitted anywhere within my application. However, it seems like this ...

RouterModule is a crucial external component that is essential for integrating

If I have a very simple component that is part of an Angular component library, it might look like this: mycomponent.module.html <div> <a routerLink="/"> </div> mycomponent.component.ts import { Component, OnInit, Input } from &a ...

Learn how to apply inline styles to multiple objects within a single element using React

In my project using React, I am attempting to apply styles only to a specific element within another element. Here is an example with an h1 tag: const Header = () => { const firstName = "Ashraf"; const lastName = "Fathi"; const date = new Date() ...

Unveiling the mysteries of JSONP in conjunction with AJAX

JSONP allows for bypassing the same origin policy in JavaScript by using <script> tags to load third party data. However, I am uncertain about how JSONP is utilized together with AJAX. My assumption is that: When an AJAX call is initiated, a <sc ...

The validation of form.$invalid appears to be malfunctioning when using the Angular UI date picker

There are two fields on the form, one for selecting a due date and another for entering a number. The due date field is a date picker where you can choose a date or manually enter a number to set the date. The create button gets enabled only when setting ...

Contrasting the uses of element(...) versus element(...).getWebElement() in Protractor

What is the advantage of using element(...).getWebElement() instead of element(...) when they both perform similarly? Why are there two different APIs for the same purpose? ...

The variable within my function is not being cleared properly despite using a jQuery function

Recently, I encountered an issue with a function that displays a dialog box to ask users if their checks printed correctly. Upon clicking on another check to print, the "checked_id" value remains the same as the previously executed id. Surprisingly, this i ...

Begin counting when a particular div element is visible on the screen

I have a plugins.init.js file that contains a try-catch block which runs on page load. I am looking for a way to execute this code only once when the div with the class counter-value comes into view. Is there a method to achieve this? try { const count ...

Odd Behavior when altering button attribute using Jquery

After disabling a button with a click handler, I have noticed an interesting behavior where the button does not submit afterwards. The issue seems to vary between different browsers, with Firefox still allowing form submission after the button is disabled, ...

Adding a Resource Bundle to a Vue project

I am looking to integrate the ResourceBundle package into my Vue project. After installing it with the following command: npm install resource-bundle I discovered these exported functions in the index.js file of the ResourceBundle package: export functi ...

Display elements exclusively when the class XY is in an active state using JavaScript

Hello everyone, I'm new to this platform and excited to share my first post. Currently, I find myself facing a major challenge as I navigate through a bootcamp program. I have been working on a website with different sections that require specific fu ...

The variable that was posted is not being successfully transferred within the query

There seems to be an issue with retrieving data from the ajax call in ajaxcall.php and assigning it to $place = $_POST['place']; in listplace.php. Despite this problem, the code runs smoothly otherwise. I've tried numerous times to get the ...

Information failed to load into the datatable

i've implemented this code snippet to utilize ajax for loading data into a datatable. However, I'm encountering an issue where the data is not being loaded into the database. $('#new_table').DataTable({ "processing": true, "ser ...

After changing the value of a <select> element in Vue, the fetched data is delayed by one step

I'm currently working on a feature that involves fetching data from a URL that changes every time a user chooses a new value from a <select> dropdown. The fetched data updates the songkickData array with the latest information. However, when I c ...

What is the method to implement timeago.js?

I've recently embarked on my journey to learn JavaScript, and it has only been two weeks since I started. As a beginner, I'm encountering some difficulties with implementing timeago from . The specific line of instruction that's giving me tr ...