Signals for managing, caching and syncing asynchronous and remote data in Angular
npx @tessl/cli install tessl/npm-tanstack--angular-query-experimental@5.86.0TanStack Angular Query (Experimental) is an Angular adapter for TanStack Query that enables reactive data fetching, caching, and state management using Angular's signals system. It provides transport-agnostic data fetching capabilities supporting REST, GraphQL, and any promise-based data sources, with automatic caching and refetching strategies.
npm install @tanstack/angular-query-experimentalimport {
provideTanStackQuery,
QueryClient,
injectQuery,
injectMutation,
injectInfiniteQuery
} from "@tanstack/angular-query-experimental";For CommonJS:
const {
provideTanStackQuery,
QueryClient,
injectQuery,
injectMutation
} = require("@tanstack/angular-query-experimental");// 1. Bootstrap with TanStack Query
import { provideTanStackQuery, QueryClient } from "@tanstack/angular-query-experimental";
bootstrapApplication(AppComponent, {
providers: [provideTanStackQuery(new QueryClient())],
});
// 2. Use in components/services
import { injectQuery, injectMutation } from "@tanstack/angular-query-experimental";
import { Component, inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
@Component({
selector: 'app-todos',
template: `
<div *ngIf="todosQuery.isPending()">Loading...</div>
<div *ngIf="todosQuery.isError()">Error: {{ todosQuery.error()?.message }}</div>
<div *ngIf="todosQuery.isSuccess()">
<ul>
<li *ngFor="let todo of todosQuery.data()">{{ todo.title }}</li>
</ul>
</div>
`
})
export class TodosComponent {
#http = inject(HttpClient);
// Query with signals - automatically reactive
todosQuery = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => this.#http.get<Todo[]>('/api/todos')
}));
// Mutation for creating todos
createTodoMutation = injectMutation(() => ({
mutationFn: (todo: CreateTodo) => this.#http.post<Todo>('/api/todos', todo),
onSuccess: () => {
// Invalidate and refetch todos
inject(QueryClient).invalidateQueries({ queryKey: ['todos'] });
}
}));
}
interface Todo {
id: number;
title: string;
completed: boolean;
}
interface CreateTodo {
title: string;
}TanStack Angular Query is built around several key components:
injectQuery, injectMutation, etc.)Core query functionality for fetching and caching data with automatic refetching, stale-while-revalidate patterns, and reactive updates.
function injectQuery<TQueryFnData, TError, TData, TQueryKey>(
injectQueryFn: () => CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
options?: InjectQueryOptions
): CreateQueryResult<TData, TError>;
interface CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
queryKey: TQueryKey;
queryFn: QueryFunction<TQueryFnData, TQueryKey>;
enabled?: boolean;
staleTime?: number;
refetchOnWindowFocus?: boolean;
// ... other query options
}
interface CreateQueryResult<TData, TError> {
data: Signal<TData | undefined>;
error: Signal<TError | null>;
isLoading: Signal<boolean>;
isPending: Signal<boolean>;
isSuccess: Signal<boolean>;
isError: Signal<boolean>;
// ... other result properties
}Mutation functionality for server-side effects with optimistic updates, error handling, and automatic query invalidation.
function injectMutation<TData, TError, TVariables, TContext>(
injectMutationFn: () => CreateMutationOptions<TData, TError, TVariables, TContext>,
options?: InjectMutationOptions
): CreateMutationResult<TData, TError, TVariables, TContext>;
interface CreateMutationOptions<TData, TError, TVariables, TContext> {
mutationFn: MutationFunction<TData, TVariables>;
onSuccess?: (data: TData, variables: TVariables, context: TContext) => void;
onError?: (error: TError, variables: TVariables, context: TContext) => void;
// ... other mutation options
}
interface CreateMutationResult<TData, TError, TVariables, TContext> {
mutate: CreateMutateFunction<TData, TError, TVariables, TContext>;
mutateAsync: CreateMutateAsyncFunction<TData, TError, TVariables, TContext>;
data: Signal<TData | undefined>;
error: Signal<TError | null>;
isSuccess: Signal<boolean>;
isError: Signal<boolean>;
isPending: Signal<boolean>;
// ... other result properties
}Infinite query functionality for pagination and infinite scrolling with automatic data accumulation and page management.
function injectInfiniteQuery<TQueryFnData, TError, TData, TQueryKey, TPageParam>(
injectInfiniteQueryFn: () => CreateInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,
options?: InjectInfiniteQueryOptions
): CreateInfiniteQueryResult<TData, TError>;
interface CreateInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam> {
queryKey: TQueryKey;
queryFn: InfiniteQueryFunction<TQueryFnData, TQueryKey, TPageParam>;
initialPageParam: TPageParam;
getNextPageParam: (lastPage: TQueryFnData, allPages: TQueryFnData[], lastPageParam: TPageParam) => TPageParam | null;
getPreviousPageParam?: (firstPage: TQueryFnData, allPages: TQueryFnData[], firstPageParam: TPageParam) => TPageParam | null;
// ... other infinite query options
}Provider functions for setting up TanStack Query in Angular applications with optional features like developer tools.
function provideTanStackQuery(
queryClient: QueryClient | InjectionToken<QueryClient>,
...features: Array<QueryFeatures>
): Array<Provider>;
function withDevtools(
withDevtoolsFn?: () => DevtoolsOptions
): DeveloperToolsFeature;
interface DevtoolsOptions {
initialIsOpen?: boolean;
buttonPosition?: DevtoolsButtonPosition;
position?: DevtoolsPosition;
loadDevtools?: 'auto' | boolean;
// ... other devtools options
}Functions for monitoring query and mutation states across the application for loading indicators and debugging.
function injectIsFetching(
filters?: QueryFilters,
options?: InjectIsFetchingOptions
): Signal<number>;
function injectIsMutating(
filters?: MutationFilters,
options?: InjectIsMutatingOptions
): Signal<number>;
function injectIsRestoring(
options?: InjectIsRestoringOptions
): Signal<boolean>;Functions for handling multiple queries simultaneously with type-safe results and combined operations.
function injectQueries<T extends Array<any>, TCombinedResult = QueriesResults<T>>(
config: {
queries: Signal<[...QueriesOptions<T>]>;
combine?: (result: QueriesResults<T>) => TCombinedResult;
},
injector?: Injector
): Signal<TCombinedResult>;
function injectMutationState<TResult = MutationState>(
injectMutationStateFn?: () => MutationStateOptions<TResult>,
options?: InjectMutationStateOptions
): Signal<Array<TResult>>;Type-safe utility functions for creating reusable query and mutation options with proper type inference.
function queryOptions<TQueryFnData, TError, TData, TQueryKey>(
options: CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>
): CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
queryKey: DataTag<TQueryKey, TQueryFnData, TError>;
};
function infiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>(
options: CreateInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
): CreateInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam> & {
queryKey: DataTag<TQueryKey, InfiniteData<TQueryFnData>, TError>;
};
function mutationOptions<TData, TError, TVariables, TContext>(
options: CreateMutationOptions<TData, TError, TVariables, TContext>
): CreateMutationOptions<TData, TError, TVariables, TContext>;// Re-exported from @tanstack/query-core
class QueryClient {
constructor(config?: QueryClientConfig);
getQueryData<TData>(queryKey: QueryKey): TData | undefined;
setQueryData<TData>(queryKey: QueryKey, data: TData): TData;
invalidateQueries(filters?: QueryFilters): Promise<void>;
// ... other QueryClient methods
}
// Angular-specific injection options
interface InjectQueryOptions {
injector?: Injector;
}
interface InjectMutationOptions {
injector?: Injector;
}
interface InjectInfiniteQueryOptions {
injector?: Injector;
}
// Common type aliases
type QueryKey = ReadonlyArray<unknown>;
type DefaultError = Error;