使用自定义顺序将typescript对象Stringify为JSON

时间:2018-06-01 10:29:10

标签: javascript json typescript

如何将typescript对象序列化为JSON字符串,以便按特定顺序(未排序)序列化所有属性?

顺序可以是接口/类顺序,或者如果可能的话,使用实验装饰器!

有什么想法吗?

示例:

interface Root {
  id: string;
  name: string;
  description: string;
  childs: Child[];
}

interface Child {
  id: string;
  name: string;
  description: string
}

const root = ...

JSON.stringify(root, null, 2);

结果:

{
  "id": "1000",
  "name": "root name",
  "description": "root description",
  "childs": [{
    "id": "9000",
    "name": "child name 1",
    "description": "child description 1"
    },{
    "id": "9001",
    "name": "child name 2",
    "description": "child description 2"
    }]
}

1 个答案:

答案 0 :(得分:0)

您可以使用实验装饰器实现此目的,例如:使用Angular中的ReflectionCapabilitiesDecorators类。

首先,声明一个属性装饰器,如下所示:

export class Serialized {
}

export interface SerializedDecorator {
    (obj: Serialized): TypeDecorator;

    new(obj: Serialized): Serialized;
}

export const Serialized: SerializedDecorator =
    makePropDecorator('Serialized', (args) => args, Serialized);

您的数据模型如下所示:

class Root {
  @Serialized({})
  id: string;

  @Serialized({})
  name: string;

  @Serialized({})
  description: string;

  @Serialized({})
  childs: Child[];
}

class Child {
  @Serialized({})
  id: string;

  @Serialized({})
  name: string;

  @Serialized({})
  description: string
}

现在,要获取属性信息并将字符串放在一起,请执行以下操作:

export function stringifyOrdered(obj: any): string {
    if(!obj || !obj.__proto__ || !obj.__proto__.constructor)
        return "";

    let serialized = "{";
    const reflect = new ReflectionCapabilities();

    // this gives you the ordered list of properties:
    for (let propMetadata in reflect.propMetadata(obj.__proto__.constructor)) {
        /* put together the stringified object,
        recursively call the serialize function if the value type is object */

        if(obj[propMetadata] instanceof Array){
            serialized += `"${propMetadata}": [`;
            for(let item of <Array<any>>obj[propMetadata]){
                if(['string', 'number', 'boolean'].includes(typeof item)){
                    serialized += `"${item}", `
                } else if (typeof item == 'object'){
                    serialized += `${stringifyOrdered(item)}, `
                }
            }
            serialized = serialized.substr(0, serialized.length - 2);
            serialized += "], ";
        }else{
            if(["string", "number", "boolean"].includes(typeof obj[propMetadata])){
                serialized += `"${propMetadata}": "${obj[propMetadata]}", `
            } else if (typeof obj[propMetadata] == 'object'){
                serialized += `"${propMetadata}": ${stringifyOrdered(obj[propMetadata])}, `
            }
        }

    }

    serialized = serialized.substr(0, serialized.length - 2);
    return serialized + "}";
}

我在自己的项目中使用ReflectionCapabilitiesDecorators。您可以从GitHub获取它:https://github.com/angular/angular/blob/master/packages/core/src/reflection/reflection_capabilities.tshttps://github.com/angular/angular/blob/master/packages/core/src/util/decorators.ts

更新:我测试了上面的代码,它对我有用。随时随地使用它。

一些背景信息:从TypeScript转换为JavaScript时,属性声明会被剥离。保留此信息的一种方法是注释所有属性。这只能在类中进行,而不能在接口中进行。