Skip to content

Commit

Permalink
feat(type): automatically assign .path to SerializationError in Templ…
Browse files Browse the repository at this point in the history
…ateState.convert() errors
  • Loading branch information
marcj committed May 29, 2024
1 parent 23781a1 commit 1e8d61d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
1 change: 1 addition & 0 deletions website/src/app/pages/documentation.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import { PlatformHelper } from '@app/app/utils';
<a routerLinkActive="active" routerLink="/documentation/runtime-types/reflection">Reflection</a>
<a routerLinkActive="active" routerLink="/documentation/runtime-types/serialization">Serialization</a>
<a routerLinkActive="active" routerLink="/documentation/runtime-types/validation">Validation</a>
<a routerLinkActive="active" routerLink="/documentation/runtime-types/extend">Extend</a>
<a routerLinkActive="active" routerLink="/documentation/runtime-types/custom-serializer">Custom serializer</a>
<a routerLinkActive="active" routerLink="/documentation/runtime-types/external-types">External Types</a>
<a routerLinkActive="active" routerLink="/documentation/runtime-types/bytecode">Bytecode</a>
Expand Down
56 changes: 56 additions & 0 deletions website/src/pages/documentation/runtime-types/extend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Extend

## Custom Serialization

You can extend the serialization of a type by defining either write your own `Serializer` or extend the default `serializer`.

This example shows how to serialize and deserialize a class `Point` to a tuple `[number, number]`.

```typescript
import { serializer, SerializationError } from '@deepkit/type';

class Point {
constructor(public x: number, public y: number) {
}
}

// deserialize means from JSON to (class) instance.
serializer.deserializeRegistry.registerClass(Point, (type, state) => {
state.convert((v: any) => {
// if it's already a Point instance, we are done
if (v instanceof Point) return v;

// at this point `v` could be anything (except undefined), so we need to check
if (!Array.isArray(v)) throw new SerializationError('Expected array');
if (v.length !== 2) throw new SerializationError('Expected array with two elements');
if (typeof v[0] !== 'number' || typeof v[1] !== 'number') throw new SerializationError('Expected array with two numbers');
return new Point(v[0], v[1]);
});
});

serializer.serializeRegistry.registerClass(Point, (type, state) => {
state.convert((v: Point) => {
// at this point `v` is always a Point instance
return [v.x, v.y];
});
});

// cast and deserialize use `serializer` by default
const point = cast<Point>([1, 2], undefined, serializer);
expect(point).toBeInstanceOf(Point);
expect(point.x).toBe(1);
expect(point.y).toBe(2);

{
expect(() => deserialize<Point>(['vbb'])).toThrowError(SerializationError);
expect(() => deserialize<Point>(['vbb'])).toThrow('Expected array with two elements')
}

// serialize uses `serializer` by default
const json = serialize<Point>(point);
expect(json).toEqual([1, 2]);
```

Please note that this is only working for the regular `@deepkit/type` functions like `cast`, `deserialize`, and `serialize`.

This won't be transferred to the database layer, since the database layer uses the types as defined in the Entity class for migration and serialization (e.g. BSON serialization).

0 comments on commit 1e8d61d

Please sign in to comment.