Guide on determining the return type using the properties of the object parameter with a generic type

My goal is to return a promise if the user selects true for async.

In TypeScript, it appears that the type will always be taken from the Create interface. How can I create a type that will be used to specify the return type?

interface Create<T> {
  options: {
    async: boolean;
  };
  properties: T;
}

type Return<T extends Create<any>> = T["options"]["async"] extends true ? Promise<boolean> : boolean;

const customCreateFunction = <T>(value: Create<T>): Return<Create<T>> => {
  return true;
};

interface User {
  username: string;
  password: string;
}

// This does not return a promise
customCreateFunction<User>({
  options: {
    async: true,
  },
  properties: {
    username: "",
    password: "",
  },
});

Answer №1

If you want to determine the correct return type, simply add one more generic type parameter specifically for the async option:

TS Playground

type Create<Properties, IsAsync extends boolean> = {
  options: { async: IsAsync };
  properties: Properties;
};

type CreateResult<IsAsync extends boolean> = IsAsync extends true ? Promise<boolean> : boolean;

declare function create <Properties, IsAsync extends boolean>(
  input: Create<Properties, IsAsync>
): CreateResult<IsAsync>;

type User = {
  username: string;
  password: string;
};

declare const userProps: User;

// With `true`, expect a Promise:
const r1 = create({ options: {async: true}, properties: userProps });

// Result for `true` should be a Promise<boolean>

// If you use `false`, get a boolean:
const r2 = create({ options: {async: false}, properties: userProps });

// Result for `false` should be a boolean

// When using an undefined boolean variable, it's a union:
declare let isAsync: boolean;
const r3 = create({ options: {async: isAsync}, properties: userProps });

// Result for undefined boolean will be either a boolean or Promise<boolean>


Check out this new code snippet in response to your comment:

TS Playground

declare function create <IsAsync extends boolean>(
  input: {
    options: { async: IsAsync };
    properties: unknown;
  },
): IsAsync extends true ? Promise<boolean> : boolean;

Answer №2

I have done my absolute best here. I really don't like that I had to resort to using a type assertion on the return value, but unfortunately, I couldn't come up with an alternative solution.

interface Create<T> {
  options: {
    async: boolean;
  };
  properties: T;
}

type Return<T> = T extends { options: { async: true } } ? Promise<boolean> : boolean;

const create = <T extends Create<any>>(value: T): Return<T> => {
  if (value.options.async === true) {
    return new Promise<boolean>((resolve) => resolve(true)) as Return<T>;
  }
  return true as Return<T>;
};

interface User {
  username: string;
  password: string;
}

create<Create<User>>({
  options: {
    async: true,
  },
  properties: {
    username: '',
    password: '',
  },
});

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

Is there a way to transfer a variable from Angular 2 Frontend Express JS to an Angular 2 component?

After conducting thorough research, I have made specific modifications to my code. However, I am encountering some errors in my console that I cannot seem to resolve. Despite following a tutorial step by step. Your assistance would be highly valued as I a ...

How can I detect a click event in Angular using Typescript?

I am looking to transform the provided jquery scripts into typescript code. Jquery $(".room").click({ console.log("clicked"); }); TypeScript import { Component } from '@angular/core'; declare var $: any; export class AppComponent { } ...

Troubleshooting issues with TypeScript D3 v4 module import functionality

As I embark on the journey of creating a miniature JS library using D3 to visualize line charts, I find myself navigating unfamiliar waters. However, I believe that deep diving into this project is the most effective way for me to learn. Below is the cont ...

Is there a way to bring in both a variable and a type from a single file in Typescript?

I have some interfaces and an enum being exported in my implementation file. // types/user.ts export enum LoginStatus { Initial = 0, Authorized = 1, NotAuthorized = 2, } export interface UserState { name: string; loginStatus: LoginStatus; }; ex ...

Discovering the process of iterating through values from multiple arrays of objects and applying them to a new response in Angular 8

Received the following data from an API response: const apiResponse = { "factoryId": "A_0421", "loss": [ { "lossType": "Planned Stoppage Time", "duration": ...

In Angular, additional code blocks are executed following the subscription

I am facing an issue with my file upload function. After the file is uploaded, it returns the uploaded path which I then pass to a TinyURL function this.tinyUrl.shorten(data.url).subscribe(sUrl => { shortUrl=sUrl;});. However, there is a delay in receiv ...

Harness the power of moment.js in webpack 4 by integrating it with ts-loader

I'm facing an issue where moment.js isn't loading inside a TypeScript file during the webpack4 build process, no matter what I attempt. [tsl] ERROR in /app/Repository/JFFH.Site/Resources/Private/JavaScript/Angular/schedule/schedule.component.ts( ...

An error has occurred during parsing: An unexpected token was found, a comma was expected instead

I encountered an error while running my program (vue3 + element plus), and I'm unsure about the cause. Can someone please assist me? Below is the error description along with an image: 56:23 error Parsing error: Unexpected token, expected "," (11 ...

Circular dependency has been identified in Typescript as services are mutually calling each other

Within my application, I have 2 key service components: PromiseService.service.ts (which manages defer calls and asynchronous calls) @Injectable() export class PromiseService { constructor(private staffservice: StaffService) {} defercall(asyncCall ...

Can you explain the syntax of Anonymous Classes in TypeScript?

interface YourInterface extends interface1 { title: string; } let yourLet = <YourInterface>{}; yourLet.title = "hello"; What exactly does <YourInterface>{} represent? Is this a method for generating objects without defining a c ...

Issue encountered with Next.js 13.4 and NextAuth: A Type Error stating that 'AuthOptions' is not compatible with type 'never'

Currently, I am in the process of developing a Next.js 13.4 project and attempting to configure NextAuth using the app/router. Unfortunately, I have encountered a type error that I am struggling to troubleshoot. Below is my route.ts file: import NextAuth, ...

Discover the step-by-step guide to setting up forwarding in React Router 5

Just diving into the world of React and TypeScript. I'm working with a component called Err. Is there a way to redirect it using React Router 5? import React, { FC, Fragment, useEffect } from "react"; const Err: FC<{ error: string }> = ({ erro ...

Can you provide guidance on creating a TypeScript interface with a dynamic key?

keys = [firstName, lastName, email,...] //this is an ever-changing array of keys. I am looking to generate a TypeScript interface dynamically based on the keys array provided. interface User { firstName : string; lastName : string; email : string; ...

Extracting the Hidden Gems in a Nested Object

My goal is to extract a specific value from a two-level deep object data structure. To begin, I am storing the data in a variable within a function, like so: getTargetId() { if (this.authenticationService.isAuthenticated()) { const userInfo = ...

Converting enums to numbers through JSON serialization

In my C# backend, I have enumerated settings with unique numbers assigned to each. public enum Settings { Setting1 = 1, Setting2 = 2, //... } To send these settings to the client through WebAPI, I use a dictionary structure. public MyModel ...

Adding Data to Array

Having an issue populating an array based on another array where pushing a value onto a specific index seems to populate all indexes. Code import { Component, VERSION } from '@angular/core'; @Component({ selector: 'my-app', templat ...

What is the reasoning behind Typescript's belief that the symbol 'name' is consistently present?

When working with Typescript, I've noticed that my code is sometimes accepted by the compiler even when I mistakenly write name instead of someObject.name. To test this behavior, I compiled a file with just console.log(name) and surprisingly, the Typ ...

How Angular services transmit information to components

I have implemented a search field within my top-bar component and I am facing an issue in passing the input value of that search field to another component. Design Search service Top bar component Result component Operation Top bar component receives th ...

The getStaticProps() method in NextJS does not get invoked when there is a change in

I have integrated my front-end web app with Contentful CMS to retrieve information about various products. As part of my directory setup, the specific configuration is located at /pages/[category]/items/[id]. Within the /pages/[category] directory, you w ...

What is the best way to combine two functions for the "value" attribute in a TextField?

How can I make a TextField force all uppercase letters for the user when they type, while also storing the text inputted by the user? I have managed to make the TextField display all uppercase letters, but then I can't submit to Excel. On the other ha ...