From f29f7bf0fae1238b306a638604675a3025b3d533 Mon Sep 17 00:00:00 2001 From: Jarom Loveridge Date: Thu, 12 Apr 2018 12:03:50 -0600 Subject: [PATCH] Make `convert` a utility method rather than private class member. --- __tests__/castable.ts | 41 +++++++++++++++++++++--------------- lib/castable.ts | 48 +++++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/__tests__/castable.ts b/__tests__/castable.ts index f6e4f12..ff7f730 100644 --- a/__tests__/castable.ts +++ b/__tests__/castable.ts @@ -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)); @@ -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 }`; @@ -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" } @@ -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)); @@ -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'); +}); diff --git a/lib/castable.ts b/lib/castable.ts index 3a7ace5..1cebe3c 100644 --- a/lib/castable.ts +++ b/lib/castable.ts @@ -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); } }