有没有一种方法可以将Typescript中的字符串解析为JSON。
示例:在JS中,我们可以使用JSON.parse()
。Typescript中有类似的功能吗?
我有一个JSON对象字符串,如下所示:
{"name": "Bob", "error": false}
有没有一种方法可以将Typescript中的字符串解析为JSON。
示例:在JS中,我们可以使用JSON.parse()
。Typescript中有类似的功能吗?
我有一个JSON对象字符串,如下所示:
{"name": "Bob", "error": false}
JSON.parse
得到一个对象而不是对象string
(有关更多信息,请参阅我的答案)。如果要将对象转换为字符串,则需要使用JSON.stringify
。
Answers:
Typescript是javascript(的超集),因此您可以JSON.parse
像在javascript中那样使用:
let obj = JSON.parse(jsonString);
只有在打字稿中,您才能对结果对象进行打字:
interface MyObj {
myString: string;
myNumber: number;
}
let obj: MyObj = JSON.parse('{ "myString": "string", "myNumber": 4 }');
console.log(obj.myString);
console.log(obj.myNumber);
(操场上的代码)
'{ "myString": "string", "myNumber": 4 }'
由'{ "myString": "string", "myNumberBAD": 4 }'
不会失败,并obj.myNumber将返回undefined。
Json.parse(text).validate[MyObj]
。playframework.com/documentation/2.6.x/ScalaJson您如何在打字稿中做同样的事情(也许有一个外部库这样做?)?
MyObj
不存在。SO中还有许多与此主题相关的其他线程,例如:检查对象是否在运行时使用TypeScript实现接口
JSON.parse
您可以继续使用JSON.parse
,因为TS是JS超集。仍然存在一个问题:JSON.parse
return any
,这会破坏类型安全性。对于更强的类型,有两种选择:
自定义类型防护是最简单的解决方案,通常足以用于外部数据验证:
// For example, you expect to parse a given value with `MyType` shape
type MyType = { name: string; description: string; }
// Validate this value with a custom type guard
function isMyType(o: any): o is MyType {
return "name" in o && "description" in o
}
然后,JSON.parse
包装器可以将类型防护作为输入并返回已解析的键入值:
const safeJsonParse = <T>(guard: (o: any) => o is T) => (text: string): ParseResult<T> => {
const parsed = JSON.parse(text)
return guard(parsed) ? { parsed, hasError: false } : { hasError: true }
}
type ParseResult<T> =
| { parsed: T; hasError: false; error?: undefined }
| { parsed?: undefined; hasError: true; error?: unknown }
用法示例:
const json = '{ "name": "Foo", "description": "Bar" }';
const result = safeJsonParse(isMyType)(json) // result: ParseResult<MyType>
if (result.hasError) {
console.log("error :/") // further error handling here
} else {
console.log(result.parsed.description) // result.parsed now has type `MyType`
}
safeJsonParse
可能会扩展为快速失败或尝试/捕获JSON.parse
错误。
如果需要验证许多不同的值,则手动编写类型保护功能会变得很麻烦。有一些库可以帮助完成此任务-示例(无完整列表):
io-ts
:rel。流行(当前为3.2k个明星),fp-ts
同级依赖项,函数式编程样式zod
:相当新的(回购:2020年3月7日),努力成为更程序/面向对象比io-ts
typescript-is
:用于编译器API的TS转换器,需要其他包装,例如ttypescripttypescript-json-schema
/ ajv
:根据类型创建JSON模式,并使用进行验证ajv
如果希望JSON具有经过验证的Typescript类型,则需要自己进行验证。这不是什么新鲜事。在纯Javascript中,您需要执行相同的操作。
我喜欢将验证逻辑表示为一组“变换”。我将a定义Descriptor
为变换图:
type Descriptor<T> = {
[P in keyof T]: (v: any) => T[P];
};
然后,我可以创建一个将这些转换应用于任意输入的函数:
function pick<T>(v: any, d: Descriptor<T>): T {
const ret: any = {};
for (let key in d) {
try {
const val = d[key](v[key]);
if (typeof val !== "undefined") {
ret[key] = val;
}
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
throw new Error(`could not pick ${key}: ${msg}`);
}
}
return ret;
}
现在,我不仅要验证我的JSON输入,而且还要在构建Typescript类型。上面的泛型类型可确保结果从“转换”中推断出类型。
万一转换抛出一个错误(这是实现验证的方式),我想用另一个错误包装它,显示哪个键导致了错误。
在您的示例中,我将按以下方式使用它:
const value = pick(JSON.parse('{"name": "Bob", "error": false}'), {
name: String,
error: Boolean,
});
现在value
将被键入,因为String
和Boolean
都是“变形金刚”,它们在某种意义上是接受输入并返回键入的输出。
此外,value
将实际上是该类型。换句话说,如果name
实际上是123
,它将被转换为,"123"
以便您具有有效的字符串。这是因为我们String
在运行时使用了一个内置函数,该函数接受任意输入并返回a string
。
您可以在这里看到此工作。尝试以下方法来说服自己:
const value
定义上可以看到弹出窗口显示正确的类型。"Bob"
为123
并重新运行示例。在控制台中,您将看到名称已正确转换为string "123"
。name
实际上123
,它将会转化成"123"
这似乎是不正确的我。value
是回来了{name: 123..
没有{name:"123"..
,当我复制粘贴正是所有的代码,并做出的改变。
Transformed
类型。您可以使用Object
。type Descriptor<T extends Object> = { ... };
Transformed
类型完全没有必要。我已经相应地更新了答案。
ts-json-object有一个很棒的库
在您的情况下,您需要运行以下代码:
import {JSONObject, required} from 'ts-json-object'
class Response extends JSONObject {
@required
name: string;
@required
error: boolean;
}
let resp = new Response({"name": "Bob", "error": false});
该库将在解析前验证json
JSON.parse
在TypeScript中可用,因此您可以使用它:
JSON.parse('{"name": "Bob", "error": false}') // Returns a value of type 'any'
但是,您经常需要解析JSON对象,同时确保它匹配某个特定类型,而不是处理type的值any
。在这种情况下,您可以定义以下函数:
function parse_json<TargetType extends Object>(
json: string,
type_definitions: { [Key in keyof TargetType]: (raw_value: any) => TargetType[Key] }
): TargetType {
const raw = JSON.parse(json);
const result: any = {};
for (const key in type_definitions) result[key] = type_definitions[key](raw[key]);
return result;
}
该函数接受一个JSON字符串和一个对象,该对象包含加载要创建的对象的每个字段的各个函数。您可以这样使用它:
const value = parse_json(
'{"name": "Bob", "error": false}',
{ name: String, error: Boolean, }
);