lightsoutAlpha

tanstack-hooks

a query-wrapping hook outside the feature's `hooks/` folder

Agent checkadvisory by defaulttanstackcode

The argument

Hooks

Custom hooks that wrap queries or manage state live in the feature's hooks/ folder — the same convention the React channel's naming rule derives (useX export → camelCase.ts), applied to TanStack query wrappers:

// features/issues/hooks/useIssues.ts
interface Params {
	searchParams: IssuesSearchParams;
}

export const useIssues = ({ searchParams }: Params) => {
	return useSuspenseQuery(issuesQueryOptions({ searchParams }));
};

The hook's inferred return type is deliberate — TanStack's generics are the contract; see the return-types note in this channel's document.

The proof

failsrc/features/issues/screens/IssuesScreen/useIssues.ts
import { useSuspenseQuery } from '@tanstack/react-query';
import { issuesQueryOptions } from '../../queries/issuesQueryOptions';

// A feature-level hook parked inside one screen's folder: the next screen that
// needs it either deep-imports across the boundary or writes a second copy.
export const useIssues = ({ search }: { search: string }) => useSuspenseQuery(issuesQueryOptions({ search }));
passsrc/features/issues/hooks/useIssues.ts
import { useSuspenseQuery } from '@tanstack/react-query';
import { issuesQueryOptions } from '../queries/issuesQueryOptions';

interface Params {
	search: string;
}

// Feature-level `hooks/`, wrapping the query options rather than restating
// them, and inferring its return type — TanStack's generics are the contract.
export const useIssues = ({ search }: Params) => useSuspenseQuery(issuesQueryOptions({ search }));

Turn it down

Both lines go in your lightsout.config.json.

"standards-checks": { "tanstack-hooks": "advisory" }
"standards-checks": { "tanstack-hooks": "off" }