TypeScript说函数的返回类型是"A|B",但通过传递参数,它必须是A,因为检查发生在内部



我已经实现了client函数,它接受一个可选的formatter参数,即functionundefined,尽管我正在检查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属性时不会出现错误。

最新更新