본문으로 건너뛰기

TypeScript

@Component({
// ...
template: `@let data = query.data();`,
// ^? data: number | undefined
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
}))
}
@Component({
// ...
template: `@let data = query.data();`,
// ^? data: string | undefined
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
select: (data) => data.toString(),
}))
}

이 예제에서는 HttpClient의 get 메서드의 타입 매개변수로 Group[]을 전달합니다.

@Component({
template: `@let data = query.data();`,
// ^? data: Group[] | undefined
})
class MyComponent {
http = inject(HttpClient)

query = injectQuery(() => ({
queryKey: ['groups'],
queryFn: () => lastValueFrom(this.http.get<Group[]>('/groups')),
}))
}
@Component({
// ...
template: `
@if (query.isSuccess()) {
@let data = query.data();
// ^? data: number
}
`,
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
}))
}

TypeScript는 현재 객체 메서드의 판별 유니온을 지원하지 않습니다. 쿼리 결과 같은 객체에서 시그널 필드를 사용한 타입 좁히기는 boolean을 반환하는 시그널에서만 작동합니다. status() === 'success'보다 isSuccess() 및 이와 유사한 boolean 상태 시그널을 사용하는 것이 좋습니다.

@Component({
// ...
template: `@let error = query.error();`,
// ^? error: Error | null
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['groups'],
queryFn: fetchGroups,
}))
}
@Component({
// ...
template: `@let error = query.error();`,
// ^? error: string | null
})
class MyComponent {
query = injectQuery<Group[], string>(() => ({
queryKey: ['groups'],
queryFn: fetchGroups,
}))
}
import axios from 'axios'

query = injectQuery(() => ({ queryKey: ['groups'], queryFn: fetchGroups }))

computed(() => {
const error = query.error()
// ^? error: Error | null

if (axios.isAxiosError(error)) {
error
// ^? const error: AxiosError
}
})
import '@tanstack/angular-query-experimental'

declare module '@tanstack/angular-query-experimental' {
interface Register {
// Use unknown so call sites must narrow explicitly.
defaultError: unknown
}
}

const query = injectQuery(() => ({
queryKey: ['groups'],
queryFn: fetchGroups,
}))

computed(() => {
const error = query.error()
// ^? error: unknown | null
})

쿼리 옵션 타입 지정

쿼리 옵션을 injectQuery에 인라인으로 작성하면 타입이 자동으로 추론됩니다. 하지만 injectQuery와 예를 들어 queryClient.query 간에 공유하거나 서비스에서 관리하기 위해 쿼리 옵션을 별도의 함수로 추출하고 싶을 수 있습니다. 이 경우 타입 추론이 사라집니다. 타입 추론을 되살리려면 queryOptions 헬퍼를 사용할 수 있습니다:

import { noop } from '@tanstack/angular-query-experimental'

@Injectable({
providedIn: 'root',
})
export class QueriesService {
private http = inject(HttpClient)

post(postId: number) {
return queryOptions({
queryKey: ['post', postId],
queryFn: () => {
return lastValueFrom(
this.http.get<Post>(
`https://jsonplaceholder.typicode.com/posts/${postId}`,
),
)
},
})
}
}

@Component({
// ...
})
export class Component {
queryClient = inject(QueryClient)

postId = signal(1)

queries = inject(QueriesService)
optionsSignal = computed(() => this.queries.post(this.postId()))

postQuery = injectQuery(() => this.queries.post(1))
postQuery = injectQuery(() => this.queries.post(this.postId()))

// You can also pass a signal which returns query options
postQuery = injectQuery(this.optionsSignal)

someMethod() {
void this.queryClient.query(this.queries.post(23)).catch(noop)
}
}

또한 queryOptions에서 반환된 queryKey는 자신과 연결된 queryFn을 알고 있으므로, 해당 타입 정보를 활용하여 queryClient.getQueryData 같은 함수도 이러한 타입을 인식하도록 할 수 있습니다:

data = this.queryClient.getQueryData(groupOptions().queryKey)
// ^? data: Post | undefined

queryOptions가 없으면 타입 매개변수를 전달하지 않는 한 데이터 타입은 unknown이 됩니다:

data = queryClient.getQueryData<Post>(['post', 1])

Mutation 옵션 타입 지정

queryOptions와 마찬가지로 mutationOptions를 사용하여 뮤테이션 옵션을 별도의 함수로 추출할 수 있습니다:

export class QueriesService {
private http = inject(HttpClient)

updatePost(id: number) {
return mutationOptions({
mutationFn: (post: Post) => Promise.resolve(post),
mutationKey: ['updatePost', id],
onSuccess: (newPost) => {
// ^? newPost: Post
this.queryClient.setQueryData(['posts', id], newPost)
},
})
}
}