A função axiosGet
:
export const axiosGet = async <TData>({
url,
params = {},
onDone,
onError
}: TypeAxiosArgs<TData>) => {
try {
const r = await axios.get<TypeAxiosData<TData, typeof params.paginate>>(url, { params })
let ret
if (params?.paginate) {
ret = r.data
} else {
ret = r.data.data // <--- causing typescript to scream, check below
}
onDone?.(ret)
return ret
} catch (e) {
console.error(e)
onError?.(e)
}
}
Os tipos:
export type TypeAxiosArgs<TData> = {
url: string
params?: { paginate?: number } & Record<string, any>
onDone?: (response: TypeAxiosData<TData, undefined>) => void
onError?: (error: any) => void
}
export type TypeAxiosData<
TData,
TPaginate extends number | undefined
> = TPaginate extends undefined
? TData
: {
data: TData
meta: {
from: number
to: number
total: number
last_page: number
}
}
Estou recebendo um erro r.data.data
se params.paginate
for indefinido
Property 'data' does not exist on type 'TypeAxiosData<TData, number | undefined>'.
Property 'data' does not exist on type 'TData'.ts(2339)
Sinto que o problema está no axios.get
genérico, que precisa ser algo diferente, mas não consigo descobrir o quê.
Editar: TypeAxiosData corrigido e tentativa de conversão manual.
export const axiosGet = async <TData>({
url,
params = {},
onDone,
onError
}: TypeAxiosArgs<TData>) => {
try {
const r = await axios.get<TypeAxiosData<TData, typeof params.paginate>>(url, { params })
let ret
if (params?.paginate) {
ret = r.data as TypeAxiosData<TData, number>
} else {
ret = r.data.data as TypeAxiosData<TData, undefined>
}
onDone?.(ret)
return ret
} catch (e) {
console.error(e)
onError?.(e)
}
}
axiosGet<{ id: number, name: string }>({ url: "", params: { paginate: undefined } })
.then((result) => {})
O problema que estou tendo é que o tipo de resultado está sendo declarado como:
(parameter) result: {
id: number;
name: string;
} | {
data: {
id: number;
name: string;
};
meta: {
from: number;
to: number;
total: number;
last_page: number;
};
} | undefined
Em vez de:
(parameter) result: {
id: number;
name: string;
} | undefined
Em primeiro lugar, você está tentando correlacionar seu tipo de resposta com base no seu
params
tipo, mas não há nada no seuaxios
código ou que os relacione. Parâmetros são apenas um dicionário independente de propriedades e não têm nenhuma relação com o tipo de resposta retornado, portanto, qualquer verificação emparams
(ouparams?.paginate
no seu exemplo) não fará com que o Typescript restrinja o tipo de resposta.Na verdade, a relação entre
params
o tipo de resposta e parece ser um contrato seu , o que significa que você está fazendo suposições sobre a API que está consumindo — você pode, obviamente, ter um endpoint em funcionamento que ignora completamenteparams.paginate
e retorna os dados em um formato arbitrário, e nesse ponto seu código simplesmente falhará, mesmo que você consiga contornar os erros de compilação. A verdadeira questão é se você realmente gostaria de manter esse contrato para TODOS os seus endpoints que você chamará por meio do seu próprioaxiosGet
wrapper.Sugiro revisar o design da API primeiro e talvez tornar a estrutura de resposta paginada e não paginada mais semelhante. Por exemplo, você pode manter este formato:
Dessa forma, você ainda pode esperar algum formato comum de todos os seus endpoints (o que é muito mais fácil de implementar por meio de algum middleware global), mas suas respostas paginadas e não paginadas serão muito mais semelhantes.
Por fim, eu não confiaria na presença dos metadados de paginação na resposta, mesmo que você os tenha solicitado nos parâmetros — a única maneira de ter certeza de que eles estão realmente presentes é verificar o payload da resposta. E acredite, é muito mais barato verificar a presença dos metadados em tempo de execução do que presumir que eles estão sempre presentes em endpoints paginados, apenas para descobrir que você se esqueceu de adicioná-los a um desses endpoints e agora tudo está travando silenciosamente. É por isso que, no exemplo de código acima, pulei a condicional de paginação.
Se você REALMENTE quiser tornar seu tipo de resposta dependente dos parâmetros, então você precisa passar os parâmetros como o tipo genérico para a resposta e torná-los
params
genéricosTypeAxiosArgs
também.