在TypeScript中考虑以下界面
interface IApiCall<TResponse> {
method: string;
url: string;
}
然后在以下方法中使用哪种方法;
const call = <TResponse>(api: IApiCall<TResponse>): void => {
// call to API via ajax call
// on response, grab data
// use JSON.parse(data) to convert to json object
return json as TResponse;
};
现在,在我们的方法中将其用于类型安全,因此我们知道从API返回了哪些对象。但是,当我们从API返回单个字符串时,JSON.parse
会将字符串'12345'转换为数字,然后在尝试将其视为字符串并使用{{ 1}},但它已被翻译成数字。
有解决此问题的想法,以便我们不将字符串转换为数字。
如何阻止JSON.parse将单个字符串值转换为数字?
如果使用JSON.parse,我们将检查value.trim()
的类型并将其与生成的json的类型进行比较。
TResponse
但是,确定通用类型的方法似乎并不明显。
答案 0 :(得分:2)
类型注释仅在TS中存在(TResponse
在输出JS中不存在),您不能将它们用作值。您必须使用实际值的类型,此处应足以选择字符串,例如
if (typeof json == 'string')
答案 1 :(得分:2)
问题1:如何阻止JSON.parse()
将单个字符串值转换为数字?
JSON是一种文本格式,因此在JSON.parse(x)
中,x
必须是string
。但是JSON文本表示不必要的数据string
。听起来您可能正在category mistake的帮助下制作confusing a thing with its representation。
如果将数字12345
转换为JSON(JSON.stringify(12345)
),则会得到字符串"12345"
。如果您解析该字符串(JSON.parse("12345")
),则会返回数字12345
。如果要获取字符串"12345"
,则需要将其编码为JSON(JSON.stringify("12345")
作为字符串"\"12345\""
。如果您解析那个(JSON.parse('"12345"'
),则会得到字符串"12345"
。
因此,“如何阻止JSON.parse()
将单个字符串值转换为数字”这一问题的直接答案是“通过正确引用”。但是也许真正的问题是您在根本不是JSON的东西上使用JSON.parse()
。如果为您提供了字符串"12345"
,并且想将其视为字符串"12345"
,那么您根本就不希望对它做任何事情……直接使用它而无需调用{ {1}}。
希望有帮助。如果由于某些原因其中之一对您不起作用,则应将您的用例的更多详细信息作为Minimal, Complete, and Verifiable example发布。
问题2:如何确定返回的JSON解析对象与通用类型匹配?
在TypeScript中,类型系统仅在设计时存在,并且在稍后运行的发出的JavaScript代码中为erased。因此,您无法在运行时访问接口并输入诸如JSON.parse()
之类的参数。通用的解决方案是从运行时解决方案开始(您将如何在纯JavaScript中做到这一点)并帮助编译器在设计时推断正确的类型。
此外,接口类型TResponse
IApiCall
没有structural对interface IApiCall<TResponse> {
method: string;
url: string;
}
的{{3}}依赖性。因此,即使我们编写了良好的运行时代码并尝试从中推断类型,编译器也将永远无法找出TResponse
是什么。
在这种情况下,我建议您使TResponse
接口包含一个not recommended成员,然后您必须为自己关心的每种类型编写自己的运行时测试。像这样:
IApiCall
下面是一个如何为特定的interface IApiCall<TResponse> {
method: string;
url: string;
validate: (x: any) => x is TResponse;
}
类型创建此类事物的示例:
TResponse
您会发现interface Person {
name: string,
age: number;
}
const personApiCall: IApiCall<Person> = {
method: "GET",
url: "https://example.com/personGrabber",
validate(x): x is Person {
return (typeof x === "object") &&
("name" in x) && (typeof x.name === "string") &&
("age" in x) && (typeof x.age === "number");
}
}
应该是运行时的良好检查,以检查personApiCall.validate(x)
是否与x
界面匹配。然后,您的Person
函数可以实现如下:
call()
请注意,const call = <TResponse>(api: IApiCall<TResponse>): Promise<TResponse | undefined> => {
return fetch(api.url, { method: api.method }).
then(r => r.json()).
then(data => api.validate(data) ? data : undefined);
};
返回一个call
(api调用可能是异步的,对吗?如果验证失败,Promise<Person | undefined>
将返回一些信息……您可以抛出异常如果你想)。现在您可以undefined
,编译器将自动了解异步结果是call(personApiCall)
:
Person | undefined
好的,我希望这些答案能给您一些指导。祝你好运!