#typescript #react-hooks #react-tsx
#typescript #реагирующие крючки #react-tsx
Вопрос:
Я получил ошибку TS2322: тип ‘unknown’ нельзя присвоить типу ‘Country[]’
страницы / Страны /index.tsx
Полный код: https://gitlab.com/fResult/countries-workshop/-/blob/bug/src/pages/Countries/index.tsx
import * as ApiCountries from '../../services/APIs/countries.api'
function Countries() {
const findCountriesCallback = useCallback(() => ApiCountries.findAll(), [])
const { execute: fetchCountries, value: countries } = useAsync(findCountriesCallback)
useEffect(() => {
;(async () => await fetchCountries())()
}, [fetchCountries])
return (
<InfiniteScroll
items={countries} // I don't understand why `countries` is `unknown` type
renderEmptyList={() => (
<div className="text-light-text dark:text-dark-text">
No Content
</div>
)}
keyExtractor={({ alpha3Code }) => alpha3Code}
renderItem={renderItem}
className="flex flex-col mt-8 md:flex-row md:flex-wrap gap-14 justify-between"
/>
)
}
ххххххххххххххххххххххххххххххххххххх
Это три файла, которые я считаю соответствующими.
services / API/countries.api.ts
(API из https://restcountries.eu /)
const BASE_URL = 'https://restcountries.eu/rest/v2'
export async function findAll() {
return await fetch(`${BASE_URL}/all`)
}
export async function findByName(name: string) {
return await fetch(`${BASE_URL}/name/${name}`)
}
ххххххххххххххххххххххххххххххххххххх
useAsync.tsx
(эта реализация перехвата для обработки успеха и ошибки асинхронной функции)
Полный код: https://gitlab.com/fResult/countries-workshop/-/blob/bug/src/cores/hooks/useAsync.tsx
function useAsync<T, E>(
asyncFn: (params?: any) => Promise<Response>,
immediate: boolean = true
) {
const [value, setValue] = useState<T | Array<T> | null>(null)
const [error, setError] = useState<E | Response | null>(null)
const [pending, setPending] = useState(false)
const execute = useCallback(async (params?) => {
setPending(true)
try {
const response: Response = await asyncFn(params)
if (!response.ok) {
setError(response)
return
}
setValue(await response?.json())
} catch (err) {
setError(err)
}
}, [asyncFn])
useEffect(() => {
if (immediate) {
;(async () => await execute())()
}
}, [execute, immediate])
return { execute, value, pending, error }
}
export default useAsync
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
components/InfiniteScroll.tsx
type InfiniteScrollProps<T> = {
items: Array<T>
renderItem: (
itemProps: {
item: T
idx: number
array: Array<T>
key: string | number
},
) => React.ReactNode
renderEmptyList?: () => React.ReactNode
keyExtractor: (item: T, idx: number) => string
className?: string
}
function InfiniteScroll<T>({
items,
keyExtractor,
renderItem,
renderEmptyList,
className
}: InfiniteScrollProps<T>) {
console.log({items})
return (
<div className={`${className ? className: ''} infinite-scroll`}>
{renderEmptyList amp;amp; !items?.length amp;amp; renderEmptyList()}
{items?.map((item, idx, array) => {
return renderItem({ item, idx, array, key: keyExtractor(item, idx) })
})}
</div>
)
}
export default InfiniteScroll
Who know how to fix this error ?
================================
Дополнительный вопрос после исправленной ошибки выше:
У меня есть новый вопрос о приведении типов для строгого типа. Теперь я реорганизовываю код функции api и использую синхронизацию, которая приведена ниже… но у меня все еще та же ошибка, если я не использую as
ключевое слово
<InfiniteScroll
items={countries as Array<Country>}
/>
services/ countries.api.ts
import axios from 'axios'
export async function findAll(params?: {
searchField?: string
region?: string
}) {
if (params?.searchField || params?.region) {
return await axios.get(`${BASE_URL}/name/${params.searchField}`)
}
return await axios.get(`${BASE_URL}/all`)
}
hooks/useAsync.tsx
(Я уже привел строгий тип, чтобы быть Array<T> | T
перед возвращаемым значением из этого хука)
function useAsync<T, E>(
asyncFn: (params?: any) => Promise<any>,
immediate: boolean = true
) {
const [value, setValue] = useState<T | Array<T> | null>(null)
const [error, setError] = useState<E | null>(null)
const [pending, setPending] = useState(false)
const execute = useCallback(
async (params?) => {
setPending(true)
try {
// Type casting this line before return value from this hook
const { data }: { data: Array<T> | T } = await asyncFn(params)
setValue(data)
} catch (err) {
setError(err)
console.error('❌ Error', err.message)
}
},
[asyncFn]
)
useEffect(() => {
if (immediate) {
;(async () => await execute())()
}
}, [execute, immediate])
return { execute, value, pending, error }
}
Ответ №1:
Вам нужно привести к любому, а затем присвоить его типу
const variable = countries as any as yourtypearray
Комментарии:
1. Это сработало … и я чувствую, что он взламывает листья. у вас есть способ решить эту проблему в корне?
2. Я имел в виду, когда другой разработчик использует мой
InfiniteScroll
компонент. Они должны взламывать так каждый раз.<InfiniteScroll items={countries as any as Array<Country>} />
3. Да, ваша функция api findall возвращает any или unknown, вы можете преобразовать свой массив в strong type array для этой функции.
4. У меня есть новый вопрос по почте. можете ли вы ответить или предложить больше?
5. Хорошо, вам нужно изменить метод api на общий тип, который вернет T[] . дайте мне знать, если вам нужен пример кода.