是否可以在TypeScript中键入JSON字符串?

是否可以在TypeScript中键入JSON字符串?,json,typescript,Json,Typescript,我想知道是否可以在Typescript中键入JSON字符串。我希望在代码编辑器中有这个特性,以进行(编译时)错误检查和自动完成。我不是在寻找运行时验证 我想到了这样的事情(自己试试): 导出类型Json=string; 导出函数decodeJson( json:json ):ContainedType{ 返回JSON.parse(JSON)作为ContainedType; } 导出函数encodeJson( 值:ContainedType ):Json{ 将JSON.stringify(valu

我想知道是否可以在Typescript中键入JSON字符串。我希望在代码编辑器中有这个特性,以进行(编译时)错误检查和自动完成。我不是在寻找运行时验证

我想到了这样的事情(自己试试):

导出类型Json=string;
导出函数decodeJson(
json:json
):ContainedType{
返回JSON.parse(JSON)作为ContainedType;
}
导出函数encodeJson(
值:ContainedType
):Json{
将JSON.stringify(value)作为JSON返回;
}
导出类型ExampleType={
例如:字符串;
};
常量示例:ExampleType={example:'value'};
//预期类型为Json,但vs代码显示字符串
const encodexample=encodeJson(示例);
//预期类型为ExampleType,但vs代码显示unknown
const decodedExample=decodeJson(encodedExample);

有没有办法让这样的东西工作起来?

字符串就是字符串,Typescript无法真正区分它们。您可以使用文字类型(在中了解更多有关文字类型的信息),但这在JSON处理上下文中没有真正意义

因此,编码JSON将始终返回字符串。但是,如果您知道JSON字符串的内容必须是什么,就可以使用泛型来键入解码后的JSON(这也可以在ajax库中完成,例如axios.io)

以您为例,请执行以下操作:

type ExampleType = {
  example: string;
};

const example: ExampleType = { example: 'value' };

function decodeJson<T>(str: string) {
  return JSON.parse(str) as T;
}

function encodeJson<T>(json: T) {
  return JSON.stringify(json);
}

// expected type is string
const encodedExample = encodeJson(example); 

// expected type is ExampleType
const decodedExample = decodeJson<ExampleType>(encodedExample); 
type ExampleType={
例如:字符串;
};
常量示例:ExampleType={example:'value'};
函数decodeJson(str:string){
将JSON.parse(str)返回为T;
}
函数encodeJson(json:T){
返回JSON.stringify(JSON);
}
//所需类型为字符串
const encodexample=encodeJson(示例);
//预期类型为ExampleType
const decodedExample=decodeJson(encodedExample);
请查看这个实例

请注意,这将强制转换返回变量
decodeJson
,因此您必须确保这是将从表示JSON的字符串返回的类型

另外,要进一步解释TypeScript无法编译的原因,请检查以下内容: 在运行时,JSON.stringify和JSON.parse本身基本上是通用函数。第一个获取任何有效的JSON并返回字符串,后一个获取任何字符串并返回JSON,如果不是JSON,则抛出错误。由于这些是运行时操作,TypeScript无法知道将处理哪些值


使用硬石膏可以解决问题,但要小心。如果运行时格式不符合编译类型,硬转换可能会引入错误。

我想我应该做更多的研究。有一个解决办法。除了使用简单的字符串,还可以向类型中添加一个包含类型信息的伪字段(以防止Typescript将类型缩减为字符串):

export-type Json=string&{uuuuu-Json\uuuuuu:ContainedType};
看看操场。如果需要,您甚至可以将类型添加到现有的JSON函数中:

declare const JSON: {
  parse: <T>(str: JSON<T>) => T;
  stringify: <T>(obj: T) => JSON<T>;
};
declare const JSON:{
parse:(str:JSON)=>T;
stringify:(obj:T)=>JSON;
};

JSON只是一个字符串,所以不可能告诉TS字符串与某种结构匹配。只是它与给定的文本匹配。您可能可以使用品牌类型(文章称之为“调味”,但这是同一件事),但您还需要明确说明这些字符串,您不会得到太多的自动化。但是,
jsonTypeA=jsonTypeB
如果您亲自正确键入,则编译时会失败。我知道我可以直接转换JSON.parse;-)的结果。通过调用decodeJson(x)而不是JSON.pase(x)作为ExampleType,我并没有得到多少好处。我想将反序列化类型的定义从函数调用中移开。当为封装JSON字符串的服务器键入响应时,这会很方便。这是不可能的。TypeScript在编译期间如何知道服务器调用的结果?结果类型将在TypeScript代码中,但不是在函数调用中。它应该编码在函数参数的类型中。与此同时,我找到了一个解决方案,并将其作为答案发布。很抱歉浪费您的时间:-\
export type Json<ContainedType> =  string & {__JSON__: ContainedType};
declare const JSON: {
  parse: <T>(str: JSON<T>) => T;
  stringify: <T>(obj: T) => JSON<T>;
};