Issue
I have written a util function that is used to parse API exceptions and return modeled TS types.
interface NotFoundException {
type: 'notFound'
}
interface PermissionException {
type: 'permission'
}
interface BadRequestException {
type: 'badRequest'
}
// Example shape of API Error
interface APIError {
statusCode: number;
}
type KnownExceptions = NotFoundException | PermissionException | BadRequestException;
function exceptionHandler(err: unknown): KnownExceptions {
const statusCode = (err as APIError).statusCode ?? -1;
if (statusCode === 404) {
return {
type: 'notFound'
}
}
if (statusCode === 403) {
return {
type: 'permission'
}
}
if (statusCode === 400) {
return {
type: 'badRequest'
}
}
throw new Error('Unknown error', { cause: err });
}
Some APIs do not return all types, so I need to handle other types explicitly
interface APIInput {
prop: string;
}
interface APIOutput {
id: string;
}
function callAPI(input: APIInput): APIOutput | PermissionException | NotFoundException {
try {
//Mock API call
return {
id: 'id'
};
} catch (err: unknown) {
const e = exceptionHandler(err);
// Problem: This API (and others) cannot throw this/some exceptions
// Need a function that will restrict the types returned by exceptionHandler
// and throw 'Unexpected exception' for impossible cases
if (e.type === 'badRequest') {
throw new Error('Unexpected exception', { cause: err });
}
return e;
}
}
Is there a way I can write a function that restricts the return types of the union of exceptions to what I want and throw an Unexpected exception
error for all other types ?
Since TS cannot take types as arguments I'm finding it hard to figure this out.
Solution
Something like this?
type ApiType = 'foo' | 'bar';
type AllowedExceptionsByApiType = {
foo: PermissionException | NotFoundException,
bar: BadRequestException
}
function exceptionHandler<T extends ApiType>(apiType: T, error: unknown): AllowedExceptionsByApiType[T] {
// impl
}
We declare possible api types in ApiType
, then possible exception by each api type in AllowedExceptionsByApiType
.
Then, using generics, the return type of exceptionHandler
is constrained to those exception allowed by the api type.
Example:
function callApi(input: SomeInput): Output | PermissionException | NotFoundException {
try {
//API Call
} catch (err: unknown) {
const e = exceptionHandler('foo', err);
// error
if (e.type === 'badRequestException') {
throw new Error('Unexpected exception', err);
}
// ok
if (e.type === 'notFound') {
// impl
}
}
}
Answered By - Murolem
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.