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
- 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.
- 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.
- 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
Security notes
None; type-safety cleanup.
Guidelines
- Minimum 95% test coverage
- Timeframe: 96 hours
Description
src/hooks/usePresenceViewers.tsbuilds its return value like this:To let callers use either
const [viewers, markActive] = usePresenceViewers(...)orconst { viewers, markActive } = usePresenceViewers(...), the hook constructs an array and then bolts named properties onto it, casting the whole thing throughas 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 likeviewerCont) 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 blanketas anycast.Suggested execution
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.as anyentirely..test-d.tsor simple compile-time assertion) confirming both access patterns type-check correctly.Acceptance criteria
usePresenceViewersno longer casts its return value throughas any.Security notes
None; type-safety cleanup.
Guidelines