fontcolor_theme
Deepkit Runtime Types

自定义序列化器

默认情况下,@deepkit/type 自带 JSON 序列化器以及对 TypeScript 类型的类型校验。你可以扩展它,添加或移除序列化功能,或改变校验的方式,因为校验同样与序列化器相关联。

新建序列化器

序列化器只是一个带有已注册序列化模板的 Serializer 类实例。序列化模板是为 JIT 序列化过程生成 JavaScript 代码的小函数。对于每种类型(String、Number、Boolean 等),都有一个单独的序列化器模板,负责返回用于数据转换或校验的代码。该代码必须与用户使用的 JavaScript 引擎兼容。

只有在模板函数执行期间,你(或者说应当)才能完全访问到该类型的完整信息。其理念是将类型转换所需的全部信息直接嵌入到生成的 JavaScript 代码中,从而得到高度优化的代码(也称为 JIT 优化代码)。

下面的示例创建一个空的序列化器。

import { EmptySerializer } from '@deepkit/type';

class User {
    name: string = '';
    created: Date = new Date;
}

const mySerializer = new EmptySerializer('mySerializer');

const user = deserialize<User>({ name: 'Peter', created: 0 }, undefined, mySerializer);
console.log(user);
$ ts-node app.ts
User { name: 'Peter', created: 0 }

如你所见,没有发生任何转换(created 仍然是数字,但我们将其定义为 Date)。要改变这一点,我们为 Date 类型的反序列化注册一个序列化器模板。

mySerializer.deserializeRegistry.registerClass(Date, (type, state) => {
    state.addSetter(`new Date(${state.accessor})`);
});

const user = deserialize<User>({ name: 'Peter', created: 0 }, undefined, mySerializer);
console.log(user);
$ ts-node app.ts
User { name: 'Peter', created: 2021-06-10T19:34:27.301Z }

现在我们的序列化器会将该值转换为 Date 对象。

要在序列化时做同样的事,我们再注册一个序列化模板。

mySerializer.serializeRegistry.registerClass(Date, (type, state) => {
    state.addSetter(`${state.accessor}.toJSON()`);
});

const user1 = new User();
user1.name = 'Peter';
user1.created = new Date('2021-06-10T19:34:27.301Z');
console.log(serialize(user1, undefined, mySerializer));
{ name: 'Peter', created: '2021-06-10T19:34:27.301Z' }

我们新的序列化器现在会在序列化过程中正确地将 Date 对象的日期转换为字符串。

示例

想查看更多示例,可以看看 Deepkit Type 中包含的JSON 序列化器的代码。

扩展现有序列化器

如果你想扩展一个现有的序列化器,可以使用类继承。这之所以可行,是因为序列化器应当在构造函数中注册它们的模板。

class MySerializer extends Serializer {
    constructor(name: string = 'mySerializer') {
        super(name);
        this.registerTemplates();
    }

    protected registerTemplates() {
        this.deserializeRegistry.register(ReflectionKind.string, (type, state) => {
            state.addSetter(`String(${state.accessor})`);
        });

        this.deserializeRegistry.registerClass(Date, (type, state) => {
            state.addSetter(`new Date(${state.accessor})`);
        });

        this.serializeRegistry.registerClass(Date, (type, state) => {
            state.addSetter(`${state.accessor}.toJSON()`);
        });
    }
}
const mySerializer = new MySerializer();
English中文 (Chinese)한국어 (Korean)日本語 (Japanese)Deutsch (German)