Skip to content

[Improvement] Add generic error types to useQuery of @powersync/react #472

Open
@guillempuche

Description

@guillempuche

Problem

Currently, the PowerSync query system uses a generic Error type for error handling in QueryResult https://github.com/powersync-ja/powersync-js/blob/main/packages/react/src/hooks/useQuery.ts#L9 and https://github.com/powersync-ja/powersync-js/blob/main/packages/common/src/types/types.ts.

This makes it difficult to handle specific types of errors in a type-safe manner when using TypeScript, forcing developers to use type assertions or broadly catch all errors without type discrimination.

Proposed Solution

Add generic error type support to the query system, allowing developers to specify and handle specific error types with full TypeScript support.

Type Changes

// In packages/common/src/types/types.ts
export interface CompilableQuery<T, E = Error> {
  execute(): Promise<T[]>;
  compile(): CompiledQuery;
}
// In packages/react/src/hooks/useQuery.ts
export type QueryResult<T, E = Error> = {
  data: T[];
  isLoading: boolean;
  isFetching: boolean;
  error: E | undefined;
  refresh?: () => Promise<void>;
};

export const useQuery = <T = any, E = Error>(
  query: string | CompilableQuery<T, E>,
  parameters?: any[],
  options?: AdditionalOptions
): QueryResult<T, E> => {
  // Implementation remains largely the same
  // Just needs to properly type the error handling
};

Usage Example

// Define your error types
interface PowerSyncError {
  type: string;
  message: string;
}

interface SQLError extends PowerSyncError {
  type: 'SQLError';
  code: number;
}

interface ValidationError extends PowerSyncError {
  type: 'ValidationError';
  fields: string[];
}

type AppError = SQLError | ValidationError;

// In your React component
function MyComponent() {
  const { data, error } = useQuery<User, AppError>('SELECT * FROM users');

  if (error) {
    if (error.type === 'SQLError') {
      // TypeScript knows this is SQLError
      console.error(`Database error ${error.code}: ${error.message}`);
    } else if (error.type === 'ValidationError') {
      // TypeScript knows this is ValidationError
      console.error(`Invalid fields: ${error.fields.join(', ')}`);
    }
  }

  return // ...
}

Benefits

  1. Type-safe error handling
  2. Better developer experience with IDE support
  3. Clearer error handling patterns
  4. No breaking changes for existing code (defaults to current Error type)
  5. Enables custom error types for different use cases

Implementation Notes

  1. This change is backward compatible as it defaults to the current Error type
  2. Minimal changes required to existing codebase

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions