Careeroza
Generic Result and ApiResponse Types
A Generic ApiResponse
Most backends wrap every response in the same envelope. One generic type describes them all.
Example
type ApiResponse<T> =
| { success: true; data: T }
| { success: false; error: { code: string; message: string } };
type Product = { id: number; name: string; price: number };
function ok<T>(data: T): ApiResponse<T> {
return { success: true, data };
}
function fail<T>(code: string, message: string): ApiResponse<T> {
return { success: false, error: { code, message } };
}
function render(res: ApiResponse<Product[]>): string {
if (res.success) return res.data.map((p) => `${p.name} Rs.${p.price}`).join(", ");
return "Error " + res.error.code + ": " + res.error.message;
}
console.log(render(ok([{ id: 1, name: "Kettle", price: 1299 }])));
console.log(render(fail("SERVER", "Database unavailable")));Output
Kettle Rs.1299 Error SERVER: Database unavailable
A Generic Result Type
Example
Result<T, E> is a popular pattern (from Rust) for functions that can fail without throwing. You will use it again in the Error Handling module.
type Result<T, E = string> = { ok: true; value: T } | { ok: false; error: E };
function parsePrice(input: string): Result<number> {
const n = Number(input);
if (Number.isNaN(n)) return { ok: false, error: `"${input}" is not a number` };
if (n < 0) return { ok: false, error: "Price cannot be negative" };
return { ok: true, value: n };
}
for (const input of ["499", "abc", "-5"]) {
const r = parsePrice(input);
console.log(input.padEnd(4), r.ok ? "value " + r.value : "error " + r.error);
}Output
499 value 499 abc error "abc" is not a number -5 error Price cannot be negative