Skip to content

Type Safety Issue: Preset interface allows invalid states (filters and symbols both optional) #20

Description

@bearmug

Problem

The current Preset interface has a critical type safety issue where both filters and symbols are optional:

export interface Preset {
  name: string;
  description: string;
  filters?: Array<{...}>;
  symbols?: string[];
  // ...
}

This design allows invalid states:

  • ❌ Both filters and symbols could be undefined (invalid preset)
  • ❌ Both could be defined simultaneously (ambiguous behavior)
  • ❌ No TypeScript enforcement of mutual exclusivity

Impact

  • Type safety degradation: Loses compile-time guarantees about preset validity
  • Runtime errors: Code must defensively check which field is present
  • Maintenance burden: Easy to create invalid presets accidentally
  • Unclear intent: Not obvious which presets are filter-based vs symbol-based

Proposed Solution

Use a discriminated union pattern to enforce mutual exclusivity:

export type Preset = {
  name: string;
  description: string;
  markets?: string[];
  sort_by?: string;
  sort_order?: "asc" | "desc";
  columns?: string[];
} & (
  | { type: 'filter'; filters: Array<{...}> }
  | { type: 'lookup'; symbols: string[] }
);

Benefits:

  • ✅ TypeScript enforces exactly one of filters or symbols is present
  • ✅ Type narrowing works automatically based on type discriminator
  • ✅ Clear intent in code (preset.type === 'filter' vs preset.type === 'lookup')
  • ✅ Industry best practice for representing mutually exclusive options

Additional Considerations

  • Verify PresetsTool correctly routes symbol-based presets to lookupSymbols function
  • Update tests to reflect discriminated union pattern
  • Migration path for existing preset definitions

References

Priority

High - Type safety issues can lead to runtime errors and maintenance problems. Should be addressed before merging lookup_symbols feature.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions