我最近开始使用TypeScript,因此是一名初学者:D。
对于应用程序,我使用以下通用方法从不同的端点获取JSON对象:
interface UnknownObject {
[index: string]: UnknownObject;
}
const fetchJSON = async (
url: string,
body?: object
): Promise<UnknownObject> => {
try {
let response;
if (!body) {
response = await fetch(url);
} else {
response = await fetch(url, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(body)
});
}
const data = await response.json();
if (response.status === 404) data.error = 404;
console.log(data);
return data;
} catch (err) {
throw err;
}
};
export default fetchJSON;
我不太了解如何为该方法定义接口。
当前(请参阅代码)我基本上通过带有递归接口的Typescript禁用了Typescript,该递归接口告诉“这是一个可能带有子对象的对象”。 (由于不推荐,因此我已禁用该类型。)
一旦我在代码中使用该方法,便可以定义该接口。
例如,调用获取页面对象的方法可能像这样:fetchJSON("pageurl"): PageProps
。定义函数本身时无需声明接口。我没有找到任何办法。
我的另一个想法是根据所使用的端点创建不同的获取方法。例如,fetchPageJSON,fetchUserJSON等。这样,我将始终知道应该返回哪个对象,但是我必须多次编写相同的方法。
执行此操作的正确方法是什么?
答案 0 :(得分:3)
您的UnknownObject
不仅比unknown
甚至any
更具表现力,而且自JSON.parse()
in the standard library returns any
起,我想您的fetchJSON
应该只需返回Promise<any>
:
declare function fetchJSON(url: string, body?: object): Promise<any>;
我将假定您将信任端点以返回符合期望类型的类型的对象,并且不对端点结果进行任何运行时验证。由于编译器将无法验证从JSON反序列化的响应的形状是否正确,因此您需要使用type assertions来告诉编译器保证您的责任是 方式。当然,如果端点返回了意外的东西,那么您将对编译器撒谎,编译器将对库的用户说谎,而这些用户在运行时代码爆炸时将不满意。
以这些接口为例,让我们看看如何做到这一点:
interface User {
name: string;
age: number;
}
interface Page {
url: string;
body: string;
}
好吧,正如您所说,可以为每种类型使用不同的fetch
函数,假设每种类型的URL都是不同的:
const fetchUser = async (body?: object): Promise<User> =>
(await fetchJSON("/theUserURL", body)) as User;
const fetchPage = async (body?: object): Promise<Page> =>
(await fetchJSON("/thePageURL", body)) as Page;
请注意,您不必多次实施fetchJSON
,而只需调用它即可。您会看到as User
和as Page
类型的断言。
现在,如果url
的可能值是常量string literals,而不是需要计算或解析的值,那么您可以将url-类型映射表示为它自己的接口:< / p>
interface FetchMap {
"/theUserURL": User;
"/thePageURL": Page;
// ... etc
}
您从不使用该类型的实际值,但可以使用它来定义fetchJSON
的版本,该版本仅允许您传递那些已知的URL:
const fetchObject: <U extends keyof FetchMap>(
url: U,
body?: object
) => Promise<FetchMap[U]> = fetchJSON;
const pagePromise = fetchObject("/thePageURL"); // Promise<Page>
const userPromise = fetchObject("/theUserURL"); // Promise<User>
const notAllowed = fetchObject("/aDifferentURL"); // error!
或者,如果您仍然希望允许传入未知网址,则可以使用条件类型为
的签名const fetchSomething: <U extends string>(
url: U,
body?: object
) => Promise<U extends keyof FetchMap ? FetchMap[U] : any> = fetchJSON;
const alsoPagePromise = fetchSomething("/thePageURL"); // Promise<Page>
const alsoUserPromise = fetchSomething("/theUserURL"); // Promise<User>
const whoKnowsPromise = fetchSomething("/aDifferentURL"); // Promise<any>
fetchObject
和fetchSomething
函数仍在使用类型断言的等效项(因为any
可以静默转换为nay类型),但是它们只允许您使用一个函数多个。
无论如何,希望能给您一些想法;祝你好运!