我已经实现了client
函数,它接受一个可选的formatter
参数,即function
或undefined
,尽管我正在检查formatter
是否为undefined
,并根据client
内部的结果返回结果,但TS似乎忽略了检查,并错误地显示了返回值。我在这里缺了什么?
功能实现:
import axios from "axios";
import { Required } from "utility-types";
import { AxiosRequestConfig } from "axios";
const client = async <D, F>(
{ url, ...config }: Required<AxiosRequestConfig, "url">,
formatter?: (data: D) => F
) => {
const response = await axios.request<D>({
url: encodeURI(url),
...config,
});
if (typeof formatter === "undefined") {
return response;
}
return formatter(response.data);
};
用法:
const formatHomeData = (data: HomePageResponse) => {
return {
products: data.result.bestSell, // This will result in an Array
slides: data.result.sliders,
notification: data.result.alert,
};
};
export const fetchIndex = async () => {
const url = 'http://localhost:4000/home';
const formatted = await client({ url }, formatHomeData);
const products = formatted.products; // TS complains here
};
fetchIndex();
TS错误
Property 'products' does not exist on type '{ products: FormattedProduct[]; slides: SliderItemResponse[]; notification: string; } | AxiosResponse<HomePageResponse>'.
Property 'products' does not exist on type 'AxiosResponse<HomePageResponse>'.ts(2339)
顺便说一句,我使用的是泛型,这样我就不必每次都像这样明确地定义formatter
函数的返回类型:
interface FormatHomeDataReturnType {
products: FormattedProduct[];
slides: SliderItemResponse[];
notification: string;
}
这里有一个链接到TypeScript Playground,我可以用最简单的方式制作它。
如果Typescript能够自动推断出这一点,那就太好了,但它并不是那么自动。不过,它确实为您提供了一种使用重载显式指定它的方法。
重载是为函数签名的不同变体定义返回类型的一种方法。对于像您的示例中那样的通用异步lambda,它看起来像:
type ClientOverload = {
<D, F>(urlAndConfig: Required<AxiosRequestConfig, 'url'>): Promise<AxiosResponse<D>>;
<D, F>(urlAndConfig: Required<AxiosRequestConfig, 'url'>, formatter: (data: D) => F): Promise<F>;
};
const client: ClientOverload = async <D, F>(...) { ... };
如果添加明确说明定义formatting
如何影响返回类型的重载,则在尝试使用products
属性时不会出现错误。