본문으로 건너뛰기

TypeScript

Solid Query는 라이브러리와 프로젝트의 타입 안전성을 보장하기 위해 TypeScript로 작성되었습니다!

유의할 사항:

  • TanStack Query는 DefinitelyTyped의 지원 기간을 따르며, 최근 2년 이내에 출시된 TypeScript 버전을 지원합니다. 현재 이는 TypeScript 5.6 이상을 의미합니다.
  • 이 repository의 type 변경은 호환성을 깨뜨리지 않는 변경으로 간주되며, 일반적으로 semver의 patch 변경으로 릴리스됩니다(그렇지 않으면 모든 type 개선이 major version이 될 것입니다!).
  • solid-query 패키지 버전을 특정 패치 릴리스로 고정하고, 어느 릴리스 사이에서든 타입이 수정되거나 업그레이드될 수 있음을 예상하면서 업그레이드하는 것을 강력히 권장합니다.
  • Solid Query의 타입과 관련 없는 공개 API는 여전히 semver를 매우 엄격하게 준수합니다.

타입 추론

Solid Query의 타입은 일반적으로 매우 원활하게 전파되므로 직접 타입 주석을 제공할 필요가 없습니다

import { useQuery } from '@tanstack/solid-query'

const query = useQuery(() => ({
queryKey: ['number'],
queryFn: () => Promise.resolve(5),
}))

query.data
// ^? (property) data: number | undefined

TypeScript 플레이그라운드

import { useQuery } from '@tanstack/solid-query'

const query = useQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
select: (data) => data.toString(),
}))

query.data
// ^? (property) data: string | undefined

TypeScript 플레이그라운드

queryFn의 반환 타입이 명확하게 정의되어 있을 때 가장 효과적입니다. 대부분의 데이터 가져오기 라이브러리는 기본적으로 any를 반환하므로, 적절한 타입이 지정된 함수로 추출해야 합니다:

const fetchGroups = (): Promise<Group[]> =>
axios.get('/groups').then((response) => response.data)

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

query.data
// ^? (property) data: Group[] | undefined

TypeScript 플레이그라운드

타입 좁히기

Solid Query는 쿼리 결과에 판별 유니온 타입을 사용하며, status 필드와 파생된 상태 불리언 플래그로 이를 판별합니다. 따라서 예를 들어 success 상태인지 확인하여 data가 정의되도록 할 수 있습니다.

const query = useQuery(() => ({
queryKey: ['number'],
queryFn: () => Promise.resolve(5),
}))

if (query.isSuccess) {
const data = query.data
// ^? const data: number
}

TypeScript 플레이그라운드

오류 필드 타입 지정하기

대부분의 사용자가 이를 예상하므로 오류 타입의 기본값은 Error입니다.

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

query.error
// ^? (property) error: Error | null

TypeScript 플레이그라운드

사용자 지정 오류 또는 Error가 전혀 아닌 값을 발생시키려면 error 필드의 타입을 지정할 수 있습니다:

const query = useQuery<Group[], string>(() => ({
queryKey: ['groups'],
queryFn: fetchGroups,
}))

query.error
// ^? (property) error: string | null

하지만 이렇게 하면 useQuery의 다른 모든 제네릭에 대한 타입 추론이 더 이상 작동하지 않는다는 단점이 있습니다. 일반적으로 Error가 아닌 것을 발생시키는 것은 좋은 관행으로 간주되지 않으므로, AxiosError 같은 하위 클래스가 있다면 _타입 좁히기_를 사용하여 error 필드를 더 구체적으로 만들 수 있습니다:

import axios from 'axios'

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

query.error
// ^? (property) error: Error | null

if (axios.isAxiosError(query.error)) {
query.error
// ^? (property) error: AxiosError
}

TypeScript 플레이그라운드

import '@tanstack/solid-query'

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

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

query.error
// ^? (property) error: unknown | null

전역 Meta 등록하기

전역 오류 타입을 등록하는 것과 마찬가지로 전역 Meta 타입도 등록할 수 있습니다. 이렇게 하면 쿼리뮤테이션의 선택적 meta 필드가 일관성과 타입 안전성을 유지합니다. meta가 객체로 유지되도록 등록된 타입은 Record<string, unknown>를 확장해야 합니다.

import '@tanstack/solid-query'

interface MyMeta extends Record<string, unknown> {
// Your meta type definition.
}

declare module '@tanstack/solid-query' {
interface Register {
queryMeta: MyMeta
mutationMeta: MyMeta
}
}

쿼리 옵션 타입 지정

쿼리 옵션을 useQuery에 인라인으로 작성하면 자동 타입 추론이 적용됩니다. 하지만 useQuery와 예를 들어 query 간에 공유하기 위해 쿼리 옵션을 별도 함수로 추출하고 싶을 수 있습니다. 이 경우 타입 추론이 사라집니다. 이를 복원하려면 queryOptions 헬퍼를 사용할 수 있습니다:

import { queryOptions } from '@tanstack/solid-query'

function groupOptions() {
return queryOptions({
queryKey: ['groups'],
queryFn: fetchGroups,
staleTime: 5 * 1000,
})
}

useQuery(groupOptions)
queryClient.query(groupOptions())

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

function groupOptions() {
return queryOptions({
queryKey: ['groups'],
queryFn: fetchGroups,
staleTime: 5 * 1000,
})
}

const data = queryClient.getQueryData(groupOptions().queryKey)
// ^? const data: Group[] | undefined

queryOptions가 없으면 제네릭을 전달하지 않는 한 data의 타입은 unknown이 됩니다:

const data = queryClient.getQueryData<Group[]>(['groups'])

skipToken을 사용한 타입 안전 쿼리 비활성화

TypeScript를 사용하는 경우 skipToken을 사용하여 쿼리를 비활성화할 수 있습니다. 이는 조건에 따라 쿼리를 비활성화하면서도 쿼리의 타입 안전성을 유지하려는 경우에 유용합니다.

자세한 내용은 쿼리 비활성화 가이드를 참조하세요.