Загрузка…
Загрузка…
TypeScript · senior · сложность 7
// ❌ any leaks everywhere — the return is unusable-safe
async function get(url: string) {
const res = await fetch(url);
return res.json(); // Promise<any> → poisons every caller silently
}
// ⚠️ Better: generic threads the type, but it's an unchecked assertion
async function getJSON<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`);
return res.json() as Promise<T>;
}
// ✅ Best: constrained generic + runtime validation via an injected parser
async function getValidated<T>(
url: string,
parse: (raw: unknown) => T, // the caller supplies the runtime check
): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return parse(await res.json()); // type AND runtime shape now agree
}
// A discriminated Result type — model failure in the type, not just throws
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
async function safe<T>(p: Promise<T>): Promise<Result<T>> {
try { return { ok: true, value: await p }; }
catch (e) { return { ok: false, error: e as Error }; }
}
const r = await safe(getJSON<User>("/api/user"));
if (r.ok) r.value.name; // ✅ narrowed to User
else r.error.message; // ✅ narrowed to ErrorТри уровня: raw json → generic assert → injected parser; Result моделирует failure без throw-only flow.