Conditional Return Types in a Typescript Function

There is a function that can return two different types, as shown below:

function doSomething(obj: {a: string, b?: string}): string | number {
  if (obj.b) {
    return 'something'
  }
  return 1
}

When the function is called with an object containing the optional property b, it always returns a string.

If the function is called with an object that does not have the optional property b, it always returns a number.

Currently, when calling the function, the return type is always a union of string and number:

const result = doSomething({a: 'a', b: 'b'})
//      ^ string | number

Is there a way to make the function return the correct type based on the input argument?

const result1 = doSomething({a: 'a', b: 'b'})
//      ^ string

const result2 = doSomething({a: 'a'})
//      ^ number

I've attempted to use conditional types without success:

type ConditionalType<T> = T extends { b: string} ? string : number
type Argument = {
  a: string,
  b?: string,
}

function doSomething<T extends Argument>(obj: T): ConditionalType<T> {
  if (obj.b) {
    return 'something' 
  }
  return 1 
}

const result = doSomething({a: 'a', b: 'b'})

Even after letting TypeScript infer the type, the result remains a union type:

function doSomething(obj: {a:string,b?:string}) {
  if (obj.b) {
    return 'something'
  }
  return 1
}

const result = doSomething({a: 'a', b: 'b'})
//      ^ "something" | 1

TypeScript Playground

Answer №1

This code snippet demonstrates pure function overloading:

function doSomething(obj: {a:string,b?:string}): string;
function doSomething(obj: {a:string,b?:undefined}): number;
function doSomething(obj: {a:string,b?:string}): string|number {
  if (obj.b) {
    return 'something'
  }
  return 1
}

const result1 = doSomething({a: 'a', b: 'b'})
//      ^ "something" | 1
console.log(result1);

const result2 = doSomething({a: 'a'})
//      ^ "something" | 1
console.log(result2);

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

Unexpected behavior of TypeScript optional object key functionality

I am facing an issue with an object that has conditional keys. For example: const headers: RequestHeaders = {}; if (...) { headers.foo = 'foo'; } if (...) { headers.bar = 'bar'; } As a newcomer to TS, I initially thought this wo ...

Retrieve a specific subdirectory from the bundle

I've developed a Typescript package with the following file structure: package.json src/ index.ts common/ index.ts sub/ index.ts My goal is to import certain modules from the package like this: import {...} from '<package>&ap ...

Having trouble displaying a "SectionList" in "React Native", it's just not cooperating

As a newcomer to programming, I recently started working with React Native. I attempted to create a FlatList, which was successful, but the data did not display as I intended. I realized I needed a header to organize the data the way I wanted, so I discove ...

Get every possible combination of a specified length without any repeated elements

Here is the input I am working with: interface Option{ name:string travelMode:string } const options:Option[] = [ { name:"john", travelMode:"bus" }, { name:"john", travelMode:"car" }, { name:"kevin", travelMode:"bus" ...

The name 'Landbot' cannot be located. Have you meant to type '_landbot' instead?

I'm currently in the process of integrating Landbot into my React.js application with TypeScript. I'm following this [doc] 1. However, I'm facing an issue where the code inside useEffect (new Landbot.Container) is causing an error. 'C ...

How to effectively handle null values using try..catch statement in typescript

As a beginner, I am learning how to write a try/catch statement in TypeScript. My issue is that there is a function within the "try" block that returns null. How can I implement code in the "catch" block specifically for when the function in "try" returns ...

Build a stopwatch that malfunctions and goes haywire

I am currently using a stopwatch that functions well, but I have encountered an issue with the timer. After 60 seconds, I need the timer to reset to zero seconds and advance to one minute. Similarly, for every 60 seconds that pass, the minutes should chang ...

Issue with Material UI grid not rendering properly in TypeScript environment

I've been trying to replicate a grid from material-ui using React and Typescript. You can see a live demo here. I modified the example to work with Typescript, so my demo.tsx file looks like this: Code goes here... If you check out the live demo, y ...

Reduce the use of if statements

Is there a way to optimize this function by reducing the number of if statements? The currentFeatures are determined by a slider in another file. The cost is updated if the currentFeatures do not match the previousFeatures, and if the user changes it back ...

Is there a way to revert my Ionic CLI back to the previous version that I had installed?

Having just updated to version 3.2.0, I am encountering numerous issues, such as the malfunctioning of the ionic serve command. ...

Utilizing Typescript for manipulation of Javascript objects

Currently, I am working on a project using Node.js. Within one of my JavaScript files, I have the following object: function Person { this.name = 'Peter', this.lastname = 'Cesar', this.age = 23 } I am trying to create an instanc ...

Using TypeScript arrow functions to define parameters

When setting "noImplicitAny": true in TypeScript, you may encounter the following errors: Parameter 'x' implicitly has an 'any' type This error can occur with the code snippet: .do(x => console.log(x)); Another error you might s ...

Ways to parse the data from a response received from an Axios POST request

After sending the same POST request using a cURL command, the response I receive is: {"allowed":[],"error":null} However, when I incorporate the POST request in my code and print it using either console.log("response: ", resp ...

Tips for sending a function with arguments in a React application using TypeScript

Is there a way to streamline passing a handleClick function to the son component so that it does not need to be repeated? The code in question is as follows: Mother Component: const Mother = () => { const [selectedOption, setSelectedOption] = useSt ...

Firebase Functions Project encountering a "Cannot find module" error in VS Code

While working on a firebase functions project in Visual Studio Code, I encountered an issue inside the index.ts file. The imported modules were not being recognized even though autocomplete showed that the modules exist. When attempting to import them, I k ...

How to efficiently display nested object data using Angular Keyvalue pipe

I am facing an issue with a particular HTTP request that returns an observable object containing multiple properties. One of these properties is the 'weight' object which has two key values, imperial and metric. While attempting to loop through ...

Different ways to reference a variable in Typescript without relying on the keyword "this" throughout the codebase

Can we eliminate the need to write "this" repeatedly, and find a way to write heroes, myHero, lastone without using "this"? Similar to how it is done in common JavaScript. https://i.stack.imgur.com/TZ4sM.png ...

Vercel deployment encountered an AxiosError with a status code of 404

I am currently working on an API route called app/api/posts/route.ts, which is responsible for fetching all posts from my database using Prisma ORM. In the localhost environment, the database is hosted on my local PostgreSQL server. However, in production, ...

What is the best way to kickstart a Reactive Angular 2 form by utilizing an Observable?

My current strategy involves storing the form values in my ngrx store so that users can easily navigate around the site and return to the form if needed. The concept is to have the form values repopulate from the store using an observable. This is how I a ...

Guide to generating a text string by utilizing the foreach loop

Is there a way to combine text strings from interfaces into a single file for display in UI? The current code is generating separate files for each interface. How can I achieve the expected result of having all interfaces in one file? Additionally, is it ...