Reputation: 75
My current situation is a server response with a boolean success and optional response data or error information.
type ServerResponse = {
success: boolean;
data?: { [key: string]: string };
err?: { code: number, message: string };
}
When I want to deal with this type, it can be a bit awkward:
const resp: ServerResponse = await fetch(...);
if(resp.success) {
doSomething( resp.data?.foo );
} else {
handleErr( resp.err?.message );
}
It's annoying to have to use the ?
when I know that data
will always be there when success === true
and err
will always be there when success === false
I've been trying to grok the documentation on mapped types, but am not finding what I need.
Is the only or best way to do this by changing the approach to ignore success
?
const resp: ServerResponse = await fetch(...);
if(resp.data) {
doSomething( resp.data.foo );
} else if(resp.err) {
handleErr( resp.err.message );
}
While that seems reasonable, I'd like to learn more advanced ways of typing anyway.
Upvotes: 0
Views: 354
Reputation: 1452
You can model this using union types.
The code for your use case is shown below,
interface SuccessResponse {
success: true;
data: { [key: string]: string }
}
interface ErrorResponse {
success: false;
err: { code: number, message: string };
}
type ServerResponse = SuccessResponse | ErrorResponse;
fetch("http://your-endpoint.com")
.then((response) => {
return response.json();
})
.then((jsonResponse: ServerResponse) => {
if(jsonResponse.success) {
console.log(jsonResponse.data)
} else {
console.log(jsonResponse.err)
}
})
Let me know if that's not clear.
Upvotes: 1