Skip to content

Commit

Permalink
Make convert a utility method rather than private class member.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarom Loveridge committed Apr 12, 2018
1 parent 109f38a commit f29f7bf
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 36 deletions.
41 changes: 25 additions & 16 deletions __tests__/castable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ class Product extends Castable {

test('Convert a simple object', () => {
const serverResponse = `{
"name": "Milk",
"price": "200",
"tax": "10",
"date": "2017-10-20T06:28:08Z",
"name": "Milk",
"price": "200",
"tax": "10",
"date": "2017-10-20T06:28:08Z",
"onSale": "false"
}`;
const product = new Product(JSON.parse(serverResponse));
Expand All @@ -25,10 +25,10 @@ test('Convert a simple object', () => {

test('Convert a simple object with unknown field', () => {
const serverResponse = `{
"name": "Milk",
"price": "200",
"tax": "10",
"date": "2017-10-20T06:28:08Z",
"name": "Milk",
"price": "200",
"tax": "10",
"date": "2017-10-20T06:28:08Z",
"onSale": "false",
"unknown": 10
}`;
Expand All @@ -43,16 +43,16 @@ test('Convert a simple object with unknown field', () => {
test('Convert an object array', () => {
const serverResponse = `[
{
"name": "Milk",
"price": "200",
"tax": "10",
"name": "Milk",
"price": "200",
"tax": "10",
"date": "2017-10-20T06:28:08Z",
"onSale": "true"
},
{
"name": "Water",
"price": "50",
"tax": "5",
"name": "Water",
"price": "50",
"tax": "5",
"date": "2017-10-25T06:28:08Z",
"onSale": "false"
}
Expand Down Expand Up @@ -150,10 +150,10 @@ test('Convert 2D object array', () => {
@element(Array, Pair)
arr: Pair[][];
}
const s = `{
const s = `{
"arr": [
[ { "name": "abc", "n": "123" }, { "name": "def", "n": "999" } ],
[ { "name": "abc2", "n": "200" }, { "name": "def2", "n": "300" } ]
[ { "name": "abc2", "n": "200" }, { "name": "def2", "n": "300" } ]
]
}`;
const c = new C(JSON.parse(s));
Expand All @@ -168,3 +168,12 @@ test('Convert 2D object array', () => {
expect(typeof c.arr[1][0].n).toBe('number');
expect(c.arr[1][0].n).toBe(200);
});

test('should allow a property called `convert`', () => {
class C extends Castable {
@cast convert: string;
}
const s = '{"convert": "value"}';
const c = new C(JSON.parse(s));
expect(c.convert).toEqual('value');
});
48 changes: 28 additions & 20 deletions lib/castable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,36 @@ export class Castable {
Object.getOwnPropertyNames(source).forEach(propertyKey => {
const designType = Reflect.getMetadata('design:type', this, propertyKey);
const customType = Reflect.getMetadata('custom:type', this, propertyKey);
const type = customType !== undefined ? customType : designType;
this[propertyKey] = this.convert(source[propertyKey], propertyKey, type, 0);
const type = customType !== void 0 ? customType : designType;
this[propertyKey] = convert(source[propertyKey], type, propertyKey, 0, this);
});
}
}

private convert(source: any, propertyKey: string, type: any, depth: number) {
if (type === undefined) {
return source;
}
switch (type.name) {
case 'Number':
return Number(source);
case 'String':
return String(source);
case 'Boolean':
return source.toString() === 'true';
case 'Array':
const elementType = Reflect.getMetadata('custom:element-type' + depth, this, propertyKey) as Function;
const nextDepth = depth + 1;
return (source as any[]).map(el => this.convert(el, propertyKey, elementType, nextDepth));
default:
return new type(source);
}
/**
* Convert a value into a specific type.
* @param value
* @param type
* @param propertyKey
* @param depth
* @param obj
*/
function convert(value: any, type: any, propertyKey: string, depth: number, obj?: any) {
if (type === void 0) {
return value;
}
switch (type.name) {
case 'Number':
return Number(value);
case 'String':
return String(value);
case 'Boolean':
return value.toString() === 'true';
case 'Array':
const elementType = Reflect.getMetadata('custom:element-type' + depth, obj, propertyKey) as Function;
const nextDepth = depth + 1;
return (value as any[]).map(el => convert(el, elementType, propertyKey, nextDepth, obj));
default:
return new type(value);
}
}

0 comments on commit f29f7bf

Please sign in to comment.