Reputation: 18562
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
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