Загрузка…
Загрузка…
TypeScript · middle · сложность 5
Моделируйте state как discriminated union — невозможные состояния не существуют:
// ✅ Model state as a discriminated union — impossible states can't exist
type RequestState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T } // data ONLY exists here
| { status: 'error'; error: Error }; // error ONLY exists here
function render(s: RequestState<string>) {
switch (s.status) {
case 'idle': return 'Start';
case 'loading': return 'Spinner';
case 'success': return s.data; // ✅ data is available & typed
case 'error': return s.error.message;
default: {
const _exhaustive: never = s; // ✅ compile error if a case is added & unhandled
return _exhaustive;
}
}
}// ❌ The bag-of-flags anti-pattern — permits impossible states
type Bad = { loading: boolean; data?: string; error?: Error };
const b: Bad = { loading: true, data: 'x', error: new Error() }; // nonsense, but legal
// Narrowing needs a LITERAL discriminant
type Ok = { kind: 'a'; x: number } | { kind: 'b'; y: string };
declare let k: string;
// if (shape.kind === k) — ❌ won't narrow; k is widened `string`, not a literalDiscriminant — литеральное поле; never в default ловит неполный switch. Bag-of-flags пропускает бессмыслицу.