I have 2 similar endpoints, that's one for getting a list, the other for getting a filtered list. Now it's not possible to merge them into one endpoint with query parameters on backend. So I have a function that decides which endpoint to use based on presence of id field. The problem is that I cannot get correct type inference, args
couldn't be narrowed.
How to do it? Maybe, it's better to use union, I see no discriminant field, though?
export interface Arguments {
id?: number;
token?: string;
pageSize: number;
}
function requestTo1stEndpoint(a: {
id: number;
token?: string;
pageSize: number;
}) {
return Promise.resolve(1);
}
function requestTo2ndEndpoint(a: {
token?: string;
pageSize: number;
}) {
return Promise.resolve(2);
}
async function request(args: Arguments) {
let fun: typeof requestTo1stEndpoint | typeof requestTo2ndEndpoint
if (args.id !== undefined) {
fun = requestTo1stEndpoint
} else
fun = requestTo2ndEndpoint
const response = await fun(args)
}
This doesn't work either:
async function request(args: Arguments) {
let responsePromise: Response
// this doesn't work either
// if ('id' in args)
if (args.id !== undefined) {
// cannot be narrowed
responsePromise = requestTo1stEndpoint(args)
} else
responsePromise = requestTo2ndEndpoint(args)
const response = await responsePromise
}
CodePudding user response:
You can do this with a User Defined Type Guard and "in" Narrowing.
To make this work, we also need to have the code that depends on the type of args
inside the true
or false
of the if
that uses the type guard. This is because the compiler "knows" it is Type1
if the true
portion executes and it is not Type1
in the else.
interface Type1{
id: number;
token?: string;
pageSize: number;
}
interface Type2 {
token?: string;
pageSize: number;
}
function isType1(x: Type1 | Type2): x is Type1 {
if ('id' in x) return true;
return false;
}
function requestTo1stEndpoint(a: Type1) {
return Promise.resolve(1);
}
function requestTo2ndEndpoint(a: Type2) {
return Promise.resolve(2);
}
async function request(args: Type1 | Type2) {
const response = isType1(args) ? await requestTo1stEndpoint(args) : await requestTo2ndEndpoint(args);
}