Kizer
Kizer

Reputation: 1666

TypeScript return type based on input

I have the following function:

subtract(sub: number | CalendarWeek): T {
    if (typeof sub === 'number') {
        return new CalendarWeek(...); // Returns a CalendarWeek if sub is a number
    }

    return 1; // Return number if sub is CalendarWeek
}

Problem is I need to define the type T such that it depends on the provided type of sub. That is, T is number if sub is CalendarWeek and CalendarWeek if sub is number.

Upvotes: 2

Views: 516

Answers (2)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249476

You can use multiple overloads to return a specific type based on the type of the parameter

function subtract(sub: number): CalendarWeek
function subtract(sub: CalendarWeek): number
function subtract(sub: number | CalendarWeek): number | CalendarWeek {
    if (typeof sub === 'number') {
        return new CalendarWeek(); // Returns a CalendarWeek if sub is a number
    }

    return 1; // Return number if sub is CalendarWeek
}

Or we can use conditonal types for a similar effect :

function subtract<T extends number | CalendarWeek>(sub: T): T extends number ? number : CalendarWeek
function subtract(sub: number | CalendarWeek): number | CalendarWeek {
    if (typeof sub === 'number') {
        return new CalendarWeek(); // Returns a CalendarWeek if sub is a number
    }

    return 1; // Return number if sub is CalendarWeek
}

Upvotes: 2

jcalz
jcalz

Reputation: 327634

The traditional TypeScript way to deal with this is to use overloaded functions. In your case it would be something like:

subtract(sub: number): CalendarWeek;
subtract(sub: CalendarWeek): number;
subtract(sub: number | CalendarWeek): number | CalendarWeek {
  if (typeof sub === 'number') {
    return new CalendarWeek(...); // Returns a CalendarWeek if sub is a number
  }
  return 1; // Return number if sub is CalendarWeek
}

You can conceivably use conditional types instead of overloads to represent this in TypeScript 2.8 and above, but it might be more advanced than you're trying to get here.

For interested parties, that solution would look like this:

subtract<T extends number | CalendarWeek>(sub: T): T extends number ? CalendarWeek : number;
subtract(sub: number | CalendarWeek): number | CalendarWeek {
  if (typeof sub === 'number') {
    return new CalendarWeek(); // Returns a CalendarWeek if sub is a number
  }
  return 1; // Return number if sub is CalendarWeek
}

Hope that helps. Good luck!

Upvotes: 4

Related Questions