我正在开发一个钩子(Hook),我可以在其中传递一个发出 Web 请求的函数,它返回 isLoading
, data
和 error
.
const [isLoading, data, error] = useApi(getMovie, idMovie, someAction);
基本上我有一个接收 3 个参数的钩子(Hook)( useApi
):我像这样使用它:
const idMovie = { _id: "3" };
// callback function
const someAction = (data: unknown) => {
// do something
return data;
};
const [isLoading, data, error] = useApi(getMovie, idMovie, someAction);
useApi.tsximport { AxiosPromise, AxiosResponse } from 'axios';
import { useState, useEffect } from 'react';
const useApi = (
apiFunction: (params: unknown) => AxiosPromise,
params = {},
callback: (data: unknown) => void
): [boolean, unknown, null | string] => {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<null | string>(null);
useEffect(() => {
apiFunction(params)
.then(({ data }: AxiosResponse) => {
setData(data);
setIsLoading(false);
if (callback) {
callback(data);
}
})
.catch(() => {
setError('Something went wrong');
setIsLoading(false);
});
}, []); //apiFunction, params, callback]
return [isLoading, data, error];
};
export default useApi;
getMovie
对应一个解决web请求的函数import axios from "axios";
type getMovieParams = { _id: string };
const BASE_URL = "https://jsonplaceholder.typicode.com/todos/";
const getMovie = (params: getMovieParams): Promise<unknown> => {
if (params) {
const { _id } = params;
if (_id) {
const url = `${BASE_URL}/${_id}`;
return axios.get(url);
}
}
throw new Error("Must provide a query");
};
export default getMovie;
调用此钩子(Hook)的代码如下所示:import "./styles.css";
import useApi from "./useApi";
import getMovie from "./api";
interface Movie {
userId: number;
id: number;
title: string;
completed: boolean;
}
export default function App() {
const idMovie = { _id: "3" };
// callback function
const someAction = (data: unknown) => {
// do something
return data;
};
const [isLoading, data, error] = useApi(getMovie, idMovie, someAction);
const dataResponse = error ? [] : data; //type Movie
console.log(dataResponse);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
{error && <div>{error}</div>}
-- Get Data Movie 1--
<p>{dataResponse.title}</p>
</div>
);
}
我在这一行遇到打字错误:<p>{dataResponse.title}</p>
这是因为:const dataResponse = error ? [] : data;
data
类型为 unknown
,这是因为它可以是任何类型的 data
,但我想在这种情况下指定数据类型为 ' Movie
',想法是在另一个组件中重用这个钩子(Hook),并且能够说出当这个钩子(Hook)返回时将获得的数据类型data
.这是我的实时代码:
https://codesandbox.io/s/vigilant-swartz-iozn4
创建这个问题的原因是请求您的帮助解决用红线标记的 typescript 问题。 (文件 app.tsx)
如何解决?谢谢
最佳答案
可以使用 generics捕获与传递给函数的参数相关的类型。例如,在您拥有的屏幕截图中,关于 params 的 TS 投诉,我们可以声明一个泛型来捕获 params 类型
function useApi<Params>(
apiFunction: (params: Params) => AxiosPromise,
params: Params,
callback: (data: unknown) => void
)
有了这个,我们的第二个钩子(Hook)参数将被输入为 apiFunction
的任何类型。在其 arg 中要求。我们做同样的事情来输入我们返回到回调的数据
function useApi<Params, Return>(
apiFunction: (params: Params) => Promise<AxiosResponse<Return>>,
params: Params,
callback: (data: Return) => void
)
我得到了 apiFunction
的返回类型通过检查 axios.get
的类型称呼get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
如您所见,最后它返回一个 Promise<AxiosResponse<T>>
.我们拦截了 T
使用我们的通用类型并将其命名 Return
现在我们也可以在钩子(Hook)的返回类型和主体中使用这些类型): [boolean, Return | null, null | string] {
const [data, setData] = useState<Return | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<null | string>(null);
useEffect(() => {
apiFunction(params)
.then(({ data }) => {
setData(data);
setIsLoading(false);
if (callback) {
callback(data);
}
})
.catch(() => {
setError("Something went wrong");
setIsLoading(false);
});
}, []); //apiFunction, params, callback]
return [isLoading, data, error];
}
由于您的电影模型特定于 getMovie 调用,您可以将该界面移到那里并输入 axios.get
称呼interface Movie {
userId: number;
id: number;
title: string;
completed: boolean;
}
const getMovie = (params: getMovieParams) => {
if (params) {
const { _id } = params;
if (_id) {
const url = `${BASE_URL}/${_id}`;
return axios.get<Movie>(url);
}
}
throw new Error("Must provide a query");
};
通过所有这些添加,当您使用钩子(Hook)时,您会在代码中观察到一些警告,这将迫使您考虑所有可能的值来实现渲染,我像这样重写了它 ...
const [isLoading, dataResponse, error] = useApi(
getMovie,
idMovie,
someAction
);
if (isLoading) {
return <div>Loading...</div>;
}
if (error) return <div>error</div>;
return <div>{dataResponse?.title}</div>;
...
https://codesandbox.io/s/generic-hook-arg-types-s8vtt
关于reactjs - 如何使变量的类型为未知或 'Movie' 分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69384239/