Always use proper Error objects when throwing exceptions, maintain consistent error handling contracts, and ensure type safety in error scenarios. Avoid throwing primitive strings, mixing throw/return patterns, or unsafe type assertions on error objects.

Key principles:

Example of problematic patterns:

// Bad: throwing string
throw `External error with reported id was not registered`

// Bad: inconsistent with function signature that returns undefined
lookupError(error: number): ErrorRecord | undefined {
  if (!errorRecord) throw `External error with reported id was not registered`
  return errorRecord
}

// Bad: unsafe destructuring from any
catch (e) {
  const { message } = e // e is any, not type-safe
}

Example of improved patterns:

// Good: proper Error object
throw new Error('External error with reported id was not registered')

// Good: consistent with signature
lookupError(error: number): ErrorRecord | undefined {
  const errorRecord = this.registeredErrors[error]
  return errorRecord // returns undefined if not found
}

// Good: type-safe error handling
catch (error) {
  if (error instanceof Error) {
    return err(error.cause)
  }
  throw error
}