kentor
kentor

Reputation: 18562

Using conditional return type depending on boolean parameter

I am writing a library and I'd like to provide more accurate Types, so that library users can't choose the wrong type in my below example.

This method either returns IPlayerStats or IStatsItem[] if the parameter convertJSONOutput is set to true.

public async getStatsById(
    userId: string,
    timeWindow: TimeWindow = TimeWindow.Alltime,
    convertJSONOutput: boolean = true
  ): Promise<IPlayerStats | IStatsItem[]> {
  // Ommitted
}

The question:

Can I specify a conditional return type which indicates what interface will be returned (depending on the convertJSONOutput boolean parameter)?

Upvotes: 4

Views: 2863

Answers (1)

Fenton
Fenton

Reputation: 251292

The simplest way to return different types based on a boolean argument would be overloads:

function getStatsById(userId: string, timeWindow: TimeWindow, convertJSONOutput: true): Promise<IPlayerStats>;
function getStatsById(userId: string, timeWindow: TimeWindow, convertJSONOutput: false): Promise<IStatsItem[]>;
function getStatsById(
    userId: string,
    timeWindow: TimeWindow = TimeWindow.Alltime,
    convertJSONOutput: boolean = true
  ): Promise<IPlayerStats | IStatsItem[]> {

When you call it, the narrowed type is then inferred based on the value of the argument:

// Promise<IPlayerStats>
const a = getStatsById('', undefined, true);

// Promise<IStatsItem[]>
const b = getStatsById('', undefined, false);

The important part is that each overload specifies the exact literal value true or false, rather than the type boolean. The return type is then tied to this. I've highlighted the relationship below.

//                              **** =>        ************
getStatsById(convertJSONOutput: true): Promise<IPlayerStats>;

I have slightly adapted the code so I could create a stand-alone example, it assumes TimeWindow, IStatsItem, and IPlayerStats are already defined:

function getStatsById(userId: string, timeWindow: TimeWindow, convertJSONOutput: true): Promise<IPlayerStats>;
function getStatsById(userId: string, timeWindow: TimeWindow, convertJSONOutput: false): Promise<IStatsItem[]>;
function getStatsById(
    userId: string,
    timeWindow: TimeWindow = TimeWindow.Alltime,
    convertJSONOutput: boolean = true
  ): Promise<IPlayerStats | IStatsItem[]> {
  // Ommitted
}

// Promise<IPlayerStats>
const a = getStatsById('', undefined, true);

// Promise<IStatsItem[]>
const b = getStatsById('', undefined, false);

Upvotes: 7

Related Questions