From harness-claude
Models TypeScript errors explicitly using Result types, discriminated unions, custom error classes, and typed throws for type-safe APIs, functions, and consistent handling patterns.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Model and type errors explicitly using Result types, discriminated unions, and typed throws
Implements resilient error handling patterns like Result types, error boundaries, try-catch, typed errors, retry backoff, and circuit breakers. Useful for TypeScript/React resilience.
Provides TypeScript functional patterns for ADTs, discriminated unions, Result/Option types, branded types. Use for state machines, type-safe domain models, and error handling.
Implements strict TypeScript practices: eliminates 'any' types with unknown guards, Zod validation, Result types, discriminated unions, branded types, and TS 5.5+ features.
Share bugs, ideas, or general feedback.
Model and type errors explicitly using Result types, discriminated unions, and typed throws
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
function ok<T>(value: T): Result<T, never> {
return { ok: true, value };
}
function err<E>(error: E): Result<never, E> {
return { ok: false, error };
}
type ValidationError = { field: string; message: string };
function validateEmail(input: string): Result<string, ValidationError> {
if (!input.includes('@')) {
return err({ field: 'email', message: 'Must contain @' });
}
return ok(input.toLowerCase().trim());
}
const result = validateEmail(input);
if (result.ok) {
sendEmail(result.value); // Type: string
} else {
showError(result.error); // Type: ValidationError
}
type AppError =
| { type: 'NOT_FOUND'; resource: string; id: string }
| { type: 'VALIDATION'; errors: ValidationError[] }
| { type: 'UNAUTHORIZED'; reason: string }
| { type: 'RATE_LIMITED'; retryAfter: number };
function handleError(error: AppError): Response {
switch (error.type) {
case 'NOT_FOUND':
return new Response(`${error.resource} ${error.id} not found`, { status: 404 });
case 'VALIDATION':
return Response.json({ errors: error.errors }, { status: 400 });
case 'UNAUTHORIZED':
return new Response(error.reason, { status: 401 });
case 'RATE_LIMITED':
return new Response('Too many requests', {
status: 429,
headers: { 'Retry-After': String(error.retryAfter) },
});
}
}
class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number,
public readonly details?: Record<string, unknown>
) {
super(message);
this.name = 'AppError';
}
static notFound(resource: string, id: string): AppError {
return new AppError(`${resource} ${id} not found`, 'NOT_FOUND', 404);
}
static badRequest(message: string, details?: Record<string, unknown>): AppError {
return new AppError(message, 'BAD_REQUEST', 400, details);
}
}
function isAppError(error: unknown): error is AppError {
return error instanceof AppError;
}
try {
await processRequest();
} catch (error: unknown) {
if (isAppError(error)) {
return handleAppError(error); // Typed as AppError
}
if (error instanceof Error) {
return handleUnexpectedError(error);
}
throw error; // Re-throw unknown errors
}
function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
return result.ok ? fn(result.value) : result;
}
const result = andThen(validateEmail(input), (email) => checkEmailAvailable(email));
type AsyncResult<T, E = Error> = Promise<Result<T, E>>;
async function fetchUser(id: string): AsyncResult<User, AppError> {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) return err(AppError.notFound('User', id));
return ok(await res.json());
} catch {
return err(new AppError('Network error', 'NETWORK', 503));
}
}
never for functions that always throw:function fail(message: string): never {
throw new Error(message);
}
function assertDefined<T>(value: T | undefined, name: string): T {
if (value === undefined) fail(`${name} is required`);
return value; // TypeScript knows this is T because fail returns never
}
TypeScript does not have a built-in mechanism for typed exceptions. The catch block always receives unknown (with useUnknownInCatchVariables). The Result pattern brings error typing to function signatures, making error handling explicit and exhaustive.
Result vs try/catch:
andThenError class inheritance: JavaScript's instanceof check works with Error subclasses, but Error.captureStackTrace (V8) must be called in the constructor for proper stack traces:
class CustomError extends Error {
constructor(message: string) {
super(message);
this.name = 'CustomError';
// Fix prototype chain for instanceof checks
Object.setPrototypeOf(this, CustomError.prototype);
}
}
Trade-offs:
never return type enables dead code elimination — but is easy to misusehttps://typescriptlang.org/docs/handbook/2/narrowing.html