{"id":28279145,"url":"https://github.com/gamebridgeai/ts_serialize","last_synced_at":"2026-04-09T10:45:20.792Z","repository":{"id":42034754,"uuid":"270744058","full_name":"GameBridgeAI/ts_serialize","owner":"GameBridgeAI","description":"A zero dependency library for serializing data","archived":false,"fork":false,"pushed_at":"2025-06-04T16:09:46.000Z","size":761,"stargazers_count":17,"open_issues_count":0,"forks_count":4,"subscribers_count":5,"default_branch":"develop","last_synced_at":"2025-07-04T04:38:42.270Z","etag":null,"topics":["browser","deno","javascript","json","node","serialization","typescript"],"latest_commit_sha":null,"homepage":"https://deno.land/x/ts_serialize","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GameBridgeAI.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-06-08T16:36:38.000Z","updated_at":"2025-06-04T16:00:44.000Z","dependencies_parsed_at":"2025-04-18T11:41:43.120Z","dependency_job_id":"0ea31e33-6e24-4ca8-9f95-8c0dbdb22b4b","html_url":"https://github.com/GameBridgeAI/ts_serialize","commit_stats":null,"previous_names":[],"tags_count":78,"template":false,"template_full_name":null,"purl":"pkg:github/GameBridgeAI/ts_serialize","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameBridgeAI%2Fts_serialize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameBridgeAI%2Fts_serialize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameBridgeAI%2Fts_serialize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameBridgeAI%2Fts_serialize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GameBridgeAI","download_url":"https://codeload.github.com/GameBridgeAI/ts_serialize/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameBridgeAI%2Fts_serialize/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268654918,"owners_count":24285125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-04T02:00:09.867Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","deno","javascript","json","node","serialization","typescript"],"created_at":"2025-05-21T09:13:58.149Z","updated_at":"2026-04-09T10:45:20.739Z","avatar_url":"https://github.com/GameBridgeAI.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🥣 ts_serialize\n\n[![tests](https://github.com/GameBridgeAI/ts_serialize/workflows/tests/badge.svg)](https://github.com/GameBridgeAI/ts_serialize/workflows/tests/badge.svg)\n[![release](https://github.com/GameBridgeAI/ts_serialize/workflows/release/badge.svg)](https://github.com/GameBridgeAI/ts_serialize/workflows/release/badge.svg)\n[![deno doc](https://doc.deno.land/badge.svg)](https://doc.deno.land/https/deno.land/x/ts_serialize/mod.ts)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA zero dependency library for serializing data.\n\n`ts_serialize` can help you with:\n\n1. Converting `camelCase` class members to `snake_case` JSON properties for use\n   with a REST API\n2. Excluding internal fields from REST API payloads\n3. Converting data types to an internal format, for example: `Date`'s\n\nSupported Serialized Types:\n\n- [`JSON`](https://www.json.org/json-en.html)\n\n## Installing\n\n`ts_serialize` supports both `deno` and `node`.\n\n### Deno\n\n`export` what you need from `https://deno.land/x/ts_serialize/mod.ts`\n\n\u003e The examples in this README pull from our `develop` branch. You would want to\n\u003e \"pin\" to a particular version which is compatible with the version of Deno you\n\u003e are using and has a fixed set of APIs you would expect. `https://deno.land/x/`\n\u003e supports using git tags in the URL to direct you at a particular version. So\n\u003e to use version 2.0.0 of `ts_serialize` you would want to import\n\u003e `https://deno.land/x/ts_serialize@v2.0.0/mod.ts`.\n\n### Node\n\nInstall with `npm i @gamebridgeai/ts_serialize` or\n`yarn add @gamebridgeai/ts_serialize`\n\n## Using `Serializable` and `SerializeProperty()`\n\nTo quickly get started extend `Serializable` with your class and add the\n[property decorator](https://www.typescriptlang.org/docs/handbook/decorators.html#property-decorators)\n`SerializeProperty()` to any class property you want in the serialization\nprocess.\n\n```typescript\nimport { Serializable, SerializeProperty } from \"./mod.ts\";\n\nclass MyClass extends Serializable {\n  @SerializeProperty()\n  public myProperty = \"Hello world!\";\n}\n```\n\n### Serializable Methods\n\n`Serializable` will add 5 methods. Each method has an implementable interface if\nyou wish to provide your own functionality.\n\n- `fromJSON`\n\n  Takes one argument, the JSON `string` or `JSONObject` to deserialize creating\n  an object. `fromJSON` will perform provided `tsTransformKey` operations and\n  strategy value transformations.\n\n- `toJSON`\n\n  Converts the model to a JSON `string` and will perform provided\n  `tsTransformKey` operations and strategy value transformations.\n\n- `clone`\n\n  Returns a new reference of the object with all properties cloned, an optional\n  parameter can be provided which is a `Partial\u003cT\u003e` where `T` is your class.\n\n- `tsSerialize`\n\n  Converts the model to \"Plain old Javascript object\" with any provided\n  `tsTransformKey` or value transformations\n\n- `tsTransformKey`\n\n  Called against every key and has one parameter, the key to transform. The\n  return value is a string. The default is to return the original parameter\n  name. Key transformations will be inherited by children classes. Children\n  classes can also `override` their parent `tsTransformKey` function.\n\nWith this in mind we can write a more complex example. We'll make a `base` class\nthat provides a key transformation then add child classes.\n\n```typescript\nimport { Serializable, SerializeProperty, TransformKey } from \"./mod.ts\";\n\nabstract class Base extends Serializable implements TransformKey {\n  public override tsTransformKey(key: string): string {\n    return `__${key}__`;\n  }\n}\n\nclass Parent extends Base {\n  @SerializeProperty()\n  public parentProperty = \"Hello world!\";\n}\n\nclass ChildOne extends Parent {\n  @SerializeProperty()\n  public childOneProperty = \"Ahoy hoy world!\";\n}\n\nclass ChildTwo extends Parent implements TransformKey {\n  @SerializeProperty()\n  public childTwoProperty = \"Good Day world!\";\n\n  @SerializeProperty(\"myCustomName\")\n  public childTwoPropertyTwo = \"Howdy world!\";\n\n  public override tsTransformKey(key: string): string {\n    return `--${key}--`;\n  }\n}\n```\n\nPassing a string or a function that returns a string as an argument to\n`SerializeProperty()` causes the property to use that name as the key when\nserialized. The function has one parameter, the `key` as string and should\nreturn a string.\n\n\u003e Inherited classes override the key when serializing. If you override a\n\u003e property any value used for that key will be overridden by the child value.\n\u003e _With collisions the child always overrides the parent_\n\n### `SerializeProperty()` options\n\n`SerializeProperty()` also excepts an optional options object with the\nproperties\n\n- `serializedKey`\n\n  (Optional) `{string | ToSerializedKeyStrategy}` A string value or function\n  that has one parameter, the property key, and returns a string. The resulting\n  value is used as the key in the serialized object\n\n- `toJSONStrategy`\n\n  (Optional) `{ToJSONStrategy}` A function that has one parameter, the class\n  property value and returns a value to be used when serialized as `JSON`\n\n- `fromJSONStrategy`\n\n  (Optional) `{FromJSONStrategy}` A function that has one parameter, the `JSON`\n  property value and returns a value to be used when serialized as a class\n\n### Strategies\n\nStrategies are functions or a composed list of functions to execute on the\nvalues when serializing or deserializing. The functions take one argument which\nis the value to process.\n\n```typescript\nimport { Serializable, SerializeProperty } from \"./mod.ts\";\n\nconst fromJSONStrategy = (v: string): BigInt =\u003e BigInt(v);\nconst toJSONStrategy = (v: BigInt): string =\u003e v.toString();\n\nclass Test extends Serializable {\n  @SerializeProperty({\n    serializedKey: \"big_int\",\n    fromJSONStrategy,\n    toJSONStrategy,\n  })\n  public bigInt!: BigInt;\n}\n```\n\n`toJSONStrategy` and `fromJSONStrategy` can use `composeStrategy` to build out\nstrategies with multiple functions.\n\n```typescript\nimport { composeStrategy, Serializable, SerializeProperty } from \"./mod.ts\";\n\nconst addWord = (word: string) =\u003e (v: string) =\u003e `${v} ${word}`;\nconst shout = (v: string) =\u003e `${v}!!!`;\n\nclass Test extends Serializable {\n  @SerializeProperty({\n    fromJSONStrategy: composeStrategy(addWord(\"World\"), shout),\n  })\n  public property!: string;\n}\n```\n\n### Dates\n\nDates can use the `fromJSONStrategy` to revive a serialized string into a Date\nobject. `ts_serialize` provides a `iso8601Date` function to parse ISO Dates.\n\n```typescript\nimport { iso8601Date, Serializable, SerializeProperty } from \"./mod.ts\";\n\nclass Test extends Serializable {\n  @SerializeProperty({\n    fromJSONStrategy: iso8601Date(),\n  })\n  public date!: Date;\n}\n```\n\n`createDateStrategy()` can be used to make a reviving date strategy. Pass a\nregex to make your own. The example below uses a `yyyy-mm-dd` format to\nconstruct a `Date`\n\n```typescript\nimport { createDateStrategy, Serializable, SerializeProperty } from \"./mod.ts\";\nclass Test extends Serializable {\n  @SerializeProperty({\n    fromJSONStrategy: createDateStrategy(/^(\\d{4})-(\\d{2})-(\\d{2})$/),\n  })\n  public date!: Date;\n}\n```\n\n## Short cutting the `@SerializeProperty` decorator\n\nWhile `@SerializeProperty` is handy with to and from JSON strategies, it can\nstill be verbose to declare the strategies for each property. You can define\nyour own decorator functions to wrap `@SerializeProperty` and provide the\n`toJSONStrategy` and `fromJSONStrategy`. An example short cut is providing a\n`type` to use with `toSerializable`. `getNewSerializable` is provided to allow a\nraw serializable type or a function that returns a constructed serializable type\nenabling constructor arguments:\n\n```typescript\nimport {\n  getNewSerializable,\n  Serializable,\n  SerializeProperty,\n  toSerializable,\n} from \"./mod.ts\";\n\nfunction DeserializeAs(\n  type: unknown,\n): PropertyDecorator {\n  return SerializeProperty({\n    fromJSONStrategy: toSerializable(() =\u003e getNewSerializable(type)),\n  });\n}\n\nclass A extends Serializable {\n  @SerializeProperty(\"property_a\")\n  public property = \"\";\n}\n\nclass B extends Serializable {\n  @DeserializeAs(A)\n  public property = new A();\n\n  public otherProperty = \"\";\n\n  constructor({ otherProperty = \"\" }: Partial\u003cB\u003e = {}) {\n    super();\n    this.otherProperty = otherProperty;\n  }\n}\n\nclass C extends Serializable {\n  @DeserializeAs(() =\u003e new B({ otherProperty: \"From Class C\" }))\n  public property = new B();\n}\n```\n\n## Polymorphism\n\nThe `@PolymorphicResolver` and `@PolymorphicSwitch` decorators can be used to\ncleanly handle deserializing abstract types into their constituent\nimplementations.\n\n### `PolymorphicSwitch()`\n\nThe `@PolymorphicSwitch()` decorator is a quick way to serialize simple\npolymorphic types based on the properties of a child class.\n\nNote that `@PolymorphicSwitch()` can only be applied to child classes\ndeserializing from their direct parent class.\n\nProperties decorated with `@PolymorphicSwitch()` must also be serializable\nproperties. The from JSON strategy and associated serialized key of that\nproperty will be used when comparing the value.\n\n```typescript\nimport {\n  polymorphicClassFromJSON,\n  PolymorphicSwitch,\n  Serializable,\n  SerializeProperty,\n} from \"./mod.ts\";\n\nenum Colour {\n  RED = \"RED\",\n  BLUE = \"BLUE\",\n}\n\nabstract class MyColourClass extends Serializable {}\n\nclass MyRedClass extends MyColourClass {\n  @SerializeProperty()\n  @PolymorphicSwitch(() =\u003e new MyRedClass(), Colour.RED)\n  public colour = Colour.RED;\n\n  @SerializeProperty()\n  public crimson = false;\n}\n\nconst redClass = polymorphicClassFromJSON(\n  MyColourClass,\n  `{\"colour\":\"RED\",\"crimson\":true}`,\n);\n```\n\nYou can also provide a test function instead of a value to check if the value\nfor the annotated property satisfies a more complex condition:\n\n```typescript\nimport {\n  polymorphicClassFromJSON,\n  PolymorphicSwitch,\n  Serializable,\n  SerializeProperty,\n} from \"./mod.ts\";\n\nabstract class Currency extends Serializable {}\n\nclass DollarCurrency extends Currency {\n  @SerializeProperty()\n  @PolymorphicSwitch(() =\u003e new DollarCurrency(), \"$\")\n  public currencySymbol = \"$\";\n\n  @SerializeProperty()\n  public amount = 0;\n}\n\nclass OtherCurrency extends Currency {\n  @SerializeProperty()\n  @PolymorphicSwitch(\n    () =\u003e new OtherCurrency(),\n    (value) =\u003e value !== \"$\",\n  )\n  public currencySymbol = \"\";\n\n  @SerializeProperty()\n  public amount = 0;\n}\n\nconst currencyClass = polymorphicClassFromJSON(\n  Currency,\n  `{\"currencySymbol\":\"£\",\"amount\":300}`,\n);\n```\n\nMultiple `@PolymorphicSwitch` annotations can be applied to a single class, if\nnecessary\n\n```typescript\nimport {\n  polymorphicClassFromJSON,\n  PolymorphicSwitch,\n  Serializable,\n  SerializeProperty,\n} from \"./mod.ts\";\n\nabstract class MyAbstractClass extends Serializable {}\n\nclass MyClass extends MyAbstractClass {\n  @SerializeProperty()\n  @PolymorphicSwitch(() =\u003e new MyClass(), \"$\")\n  @PolymorphicSwitch(() =\u003e new MyClass(), \"dollar\")\n  @PolymorphicSwitch(\n    () =\u003e new MyClass(),\n    (value) =\u003e typeof value === \"string\" \u0026\u0026 value.includes(\"dollars\"),\n  )\n  public myProperty = \"$\";\n\n  @SerializeProperty()\n  public amount = 0;\n}\n\nconst myClass1 = polymorphicClassFromJSON(\n  MyAbstractClass,\n  `{\"myProperty\":\"300 dollars\"}`,\n);\n\nconst myClass2 = polymorphicClassFromJSON(\n  MyAbstractClass,\n  `{\"myProperty\":\"dollar\"}`,\n);\n```\n\n### Polymorphic Resolver\n\nThe following example shows how the `@PolymorphicResolver` decorator can be used\nto directly determine the type of an abstract class implementor, which will then\nbe used when deserializing JSON input.\n\n```typescript\nimport {\n  polymorphicClassFromJSON,\n  PolymorphicResolver,\n  Serializable,\n  SerializeProperty,\n} from \"./mod.ts\";\n\nenum Colour {\n  RED = \"RED\",\n  BLUE = \"BLUE\",\n}\n\nabstract class MyColourClass extends Serializable {\n  @SerializeProperty()\n  public colour?: Colour;\n\n  @PolymorphicResolver()\n  public static resolvePolymorphic(input: string): MyColourClass {\n    const colourClass = new PolymorphicColourClass().fromJSON(input);\n\n    switch (colourClass.colour) {\n      case Colour.RED:\n        return new MyRedClass();\n      case Colour.BLUE:\n        return new MyBlueClass();\n      default:\n        throw new Error(`Unknown Colour ${colourClass.colour}`);\n    }\n  }\n}\n\nclass PolymorphicColourClass extends MyColourClass {}\n\nclass MyRedClass extends MyColourClass {\n  @SerializeProperty()\n  private crimson = false;\n\n  public isCrimson(): boolean {\n    return this.crimson;\n  }\n}\n\nclass MyBlueClass extends MyColourClass {\n  @SerializeProperty()\n  private aqua = false;\n\n  public isAqua(): boolean {\n    return this.aqua;\n  }\n}\n\nconst redClass = polymorphicClassFromJSON(\n  MyColourClass,\n  `{\"colour\":\"RED\",\"crimson\":true}`,\n);\n```\n\n## Built With\n\n- [Deno](http://deno.land) 🦕\n\n## Contributing\n\nWe have provided resources to help you request a new feature or report and fix a\nbug.\n\n- [CONTRIBUTING.md](./.github/CONTRIBUTING.md) - for guidelines when requesting\n  a feature or reporting a bug or opening a pull request\n- [DEVELOPMENT.md](./.github/DEVELOPMENT.md) - for instructions on setting up\n  the environment and running the test suite\n- [CODE_OF_CONDUCT.md](./.github/CODE_OF_CONDUCT.md) - for community guidelines\n\n## Versioning\n\nWe use [SemVer](http://semver.org/) for versioning.\n\n## Authors\n\n- **Scott Hardy** - _Initial work_ - [@hardy925](https://github.com/hardy925) 🐸\n- **Chris Dufour** - _Initial work_ -\n  [@ChrisDufourMB](https://github.com/ChrisDufourMB) 🍕 🐱 👑\n\nSee also the list of [contributors](./.github/CONTRIBUTORS.md) who participated\nin this project.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file\nfor details\n\n## Acknowledgments\n\n- Our colleagues at [MindBridge](https://mindbridge.ai) for discussion and\n  project planning\n- [Parsing Dates with JSON](https://weblog.west-wind.com/posts/2014/Jan/06/JavaScript-JSON-Date-Parsing-and-real-Dates)\n  for knowledge\n- [OAK Server](https://github.com/oakserver/oak) as a project structure example\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgamebridgeai%2Fts_serialize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgamebridgeai%2Fts_serialize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgamebridgeai%2Fts_serialize/lists"}