Skip to content

usePresenceViewers returns a dual tuple/object value via an as any cast, bypassing type safety entirely #1067

Description

@mikewheeleer

Description

src/hooks/usePresenceViewers.ts builds its return value like this:

const viewerCount = viewers.filter(v => !v.fadingOut).length;

// Support both tuple [viewers, markActive, viewerCount] and object destructuring { viewers, markActive, viewerCount }
const result = [viewers, markActive, viewerCount] as any;
result.viewers = viewers;
result.markActive = markActive;
result.viewerCount = viewerCount;

return result;

To let callers use either const [viewers, markActive] = usePresenceViewers(...) or const { viewers, markActive } = usePresenceViewers(...), the hook constructs an array and then bolts named properties onto it, casting the whole thing through as any. This completely bypasses TypeScript's type checking on the hook's return value — any caller destructuring a property that doesn't exist (e.g. a typo like viewerCont) or using it in a way inconsistent with either the array or object shape will not be caught at compile time. It's also unclear from any call site alone which access pattern is "the real one," since both are silently supported by the same hacked-together value.

Requirements

  • usePresenceViewers's return value should be properly typed so TypeScript can catch shape mismatches at call sites, without a blanket as any cast.
  • If both tuple and object destructuring genuinely need to be supported, the return type should be declared precisely enough to type-check both usages (e.g. a typed array-like interface), rather than opting out of type checking entirely.

Suggested execution

  1. Audit all real call sites of usePresenceViewers (grep -rn "usePresenceViewers(" src) to determine whether both the tuple and object access patterns are actually used anywhere, or whether this dual-shape support is unused complexity.
  2. If only one access pattern is actually used, simplify the hook to return a plainly-typed object (or plainly-typed tuple) and update the (likely single) call site accordingly, removing the as any entirely.
  3. If both patterns are genuinely required, define a proper TypeScript type that models an array with the additional named properties (a "tuple-like" interface) so the cast is no longer needed, and add a type-level test (e.g. a .test-d.ts or simple compile-time assertion) confirming both access patterns type-check correctly.

Acceptance criteria

  • usePresenceViewers no longer casts its return value through as any.
  • Both consumer access patterns (whichever are genuinely used) are properly typed.
  • Existing presence tests continue to pass.

Security notes

None; type-safety cleanup.

Guidelines

  • Minimum 95% test coverage
  • Timeframe: 96 hours

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions