{"id":26060673,"url":"https://github.com/traits-ts/stdlib","last_synced_at":"2025-09-06T08:47:40.690Z","repository":{"id":280970838,"uuid":"943790551","full_name":"traits-ts/stdlib","owner":"traits-ts","description":"Traits for TypeScript Classes (Standard Library)","archived":false,"fork":false,"pushed_at":"2025-08-25T08:43:14.000Z","size":346,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-28T09:55:02.943Z","etag":null,"topics":["class","library","mixin","oop","standard","trait","typescript"],"latest_commit_sha":null,"homepage":"https://traits-ts.org","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/traits-ts.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-06T09:16:37.000Z","updated_at":"2025-08-25T08:43:16.000Z","dependencies_parsed_at":"2025-03-06T09:47:46.135Z","dependency_job_id":"147f3d08-4ed1-49db-8cd7-462cfe189ab8","html_url":"https://github.com/traits-ts/stdlib","commit_stats":null,"previous_names":["traits-ts/stdlib"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/traits-ts/stdlib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/traits-ts%2Fstdlib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/traits-ts%2Fstdlib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/traits-ts%2Fstdlib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/traits-ts%2Fstdlib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/traits-ts","download_url":"https://codeload.github.com/traits-ts/stdlib/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/traits-ts%2Fstdlib/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273879851,"owners_count":25184428,"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-09-06T02:00:13.247Z","response_time":2576,"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":["class","library","mixin","oop","standard","trait","typescript"],"created_at":"2025-03-08T14:30:00.541Z","updated_at":"2025-09-06T08:47:40.646Z","avatar_url":"https://github.com/traits-ts.png","language":"TypeScript","readme":"\n\u003cimg src=\"https://raw.githubusercontent.com/traits-ts/core/refs/heads/master/etc/logo.svg\" width=\"200\" style=\"float: right\" align=\"right\" alt=\"\"/\u003e\n\n@traits-ts/stdlib\n=================\n\n**Traits for TypeScript Classes (Standard Library)**\n\n\u003cp/\u003e\n\u003ca href=\"https://traits-ts.org\"\u003eProject Home\u003c/a\u003e |\n\u003ca href=\"https://github.com/traits-ts/stdlib\"\u003eGithub Repository\u003c/a\u003e |\n\u003ca href=\"https://npmjs.com/@traits-ts/stdlib\"\u003eNPM Distribution\u003c/a\u003e\n\n\u003cp/\u003e\n\u003cimg src=\"https://nodei.co/npm/@traits-ts/stdlib.png?downloads=true\u0026stars=true\" alt=\"\"/\u003e\n\n[![github (author stars)](https://img.shields.io/github/stars/rse?logo=github\u0026label=author%20stars\u0026color=%233377aa)](https://github.com/rse)\n[![github (author followers)](https://img.shields.io/github/followers/rse?label=author%20followers\u0026logo=github\u0026color=%234477aa)](https://github.com/rse)\n\u003cbr/\u003e\n[![npm (project release)](https://img.shields.io/npm/v/@traits-ts/stdlib?logo=npm\u0026label=npm%20release\u0026color=%23cc3333)](https://npmjs.com/@traits-ts/core)\n[![npm (project downloads)](https://img.shields.io/npm/dm/@traits-ts/stdlib?logo=npm\u0026label=npm%20downloads\u0026color=%23cc3333)](https://npmjs.com/@traits-ts/core)\n\nAbout\n-----\n\nThis is a TypeScript library providing a set of standard,\nreusable, generic, typed *traits* (aka *mixins*), based on the\n[@traits-ts/core](https://github.com/traits-ts/core) library. \n\nCurrently,\nthis standard library consists of the reusable traits *Identifiable*,\n*Configurable*, *Bindable*, *Subscribable*, *Hookable*, *Finalizable*,\n*Traceable*, and *Serializable*. All traits try to avoid any namespace\nconflicts with application code by prefixing their exposed functionality\nwith the name prefix `$`.\n\nSee also [@traits-ts/core](https://github.com/traits-ts/core) for\nmore details on the underlying core **traits** mechanism.\n\nInstallation\n------------\n\n```sh\n$ npm install --save @traits-ts/core @traits-ts/stdlib\n```\n\nTrait: *Identifiable*\n---------------------\n\nThe reusable generic trait *Identifiable* allows you to attach a\nUniversally Unique Identifier (UUID, version 1) to the objects of a\ntarget class. You can then retrieve the UUID with the (read-only) `$id`\nproperty. Apply an *Identifiable* for unique identification.\n\n```ts\nimport { derive }       from \"@traits-ts/core\"\nimport { Identifiable } from \"@traits-ts/stdlib\"\n\nclass Sample extends derive(Identifiable) {}\n\nconst sample = new Sample()\n\nsample.$id // -\u003e e.g. cbd8f4a0-f115-11ef-8f81-38f9d30d57c1\n```\n\nTrait: *Configurable*\n---------------------\n\nThe reusable generic trait *Configurable* allows you to attach a fully\ntyped and mergable configuration `T` of `Configurable\u003cT\u003e` to the objects\nof a target class. You have to initialize the configuration through\nproperty `$configuration` and later you can retrieve the current\nconfiguration through it again. You can change the configuration with\nthe method `$configure` by passing any subset (aka a \"deep partial\") of\n`T` and this way \"merge\" your changes into the configuration. Apply a\n*Configurable* for incrementally changing a configuration.\n\n```ts\nimport { derive }       from \"@traits-ts/core\"\nimport { Configurable } from \"@traits-ts/stdlib\"\n\ntype Config = {\n    foo: number,\n    bar: string\n    baz: {\n        quux: boolean\n    }\n}\nclass Sample extends derive(Configurable\u003cConfig\u003e) {\n    $configuration = {\n        foo: 42,\n        bar: \"bar\",\n        baz: {\n            quux: true\n        }\n    }\n}\n\nconst sample = new Sample()\n\nsample.$configuration // -\u003e { foo: 42, bar: \"bar\", baz: { quux: true } }\n\nsample.$configure({ bar: \"baz\", baz: { quux: false } })\nsample.$configuration // -\u003e { foo: 42, bar: \"baz\", baz: { quux: false } }\n```\n\nTrait: *Bindable*\n-----------------\n\nThe reusable generic trait *Bindable* allows you to bind to properties\nof a target class. The properties have to be defined in an interface\n`T` of `Bindable\u003cT\u003e` and defined as `@bindable accessor` on the target\nclass. You can then bind to those properties with method `$bind` and\nobserve all changes to the property. Apply a *Bindable* for allowing\nthe external observing and reacting to property changes.\n\n```ts\nimport { derive }             from \"@traits-ts/core\"\nimport { Bindable, bindable } from \"@traits-ts/stdlib\"\n\ninterface Props { foo: number, bar: string }\n\nclass Sample extends derive(Bindable\u003cProps\u003e) implements Props {\n    @bindable accessor foo = 42\n    @bindable accessor bar = \"bar\"\n}\n\nconst sample = new Sample()\nconst b1 = sample.$bind(\"foo\", (val, old) =\u003e { console.log(\"foo:\", val, old) })\nconst b2 = sample.$bind(\"bar\", (val, old) =\u003e { console.log(\"bar:\", val, old) })\n\nsample.foo += 1    // -\u003e foo: 43 42\nsample.bar = \"baz\" // -\u003e bar: baz bar\n\nb1.unbind()\nb2.unbind()\n```\n\nTrait: *Subscribable*\n---------------------\n\nThe reusable generic trait *Subscribable* allows you to subscribe to\ntyped events emitted on a target class. The events have to be defined\nin an interface `T` of `Subscribable\u003cT\u003e`. You can then subscribe to\nthose events with method `$subscribe` and emit those events with method\n`$emit`. Apply a *Subscribable* for allowing the external observing and\nreacting to logical events.\n\n```ts\nimport { derive }       from \"@traits-ts/core\"\nimport { Subscribable } from \"@traits-ts/stdlib\"\n\ninterface Events { \"foo\": number, \"bar\": string }\n\nclass Sample extends derive(Subscribable\u003cEvents\u003e) {}\n\nconst sample = new Sample()\nconst s1 = sample.$subscribe(\"foo\", { limit: 1 }, (val) =\u003e {\n    console.log(\"foo:\", val)\n})\nconst s2 = sample.$subscribe(\"bar\", (val) =\u003e {\n    console.log(\"bar:\", val)\n})\n\nsample.$emit(\"foo\", 42)      // -\u003e foo: 42\nsample.$emit(\"foo\", 7)       // -\u003e (none)\nsample.$emit(\"bar\", \"quux\")  // -\u003e bar: quux\nsample.$emit(\"bar\", \"baz\")   // -\u003e bar: baz\n\ns1.unsubscribe()\ns2.unsubscribe()\n```\n\nTrait: *Hookable*\n-----------------\n\nThe reusable generic trait *Hookable* allows you to attach hooks to\na target class. The hooks have to be defined in an interface `T` of\n`Hookable\u003cT\u003e`. You can then latch into those hooks with method `$latch`\nand call those hooks with method `$hook`. Apply a *Hookable* for\nallowing the external extension of functionality.\n\n```ts\nimport { derive }   from \"@traits-ts/core\"\nimport { Hookable } from \"@traits-ts/stdlib\"\n\ninterface Hooks {\n    \"foo\":  { arg: string },\n    \"bar\":  { arg: number },\n    \"quux\": undefined\n}\nclass Sample extends derive(Hookable\u003cHooks\u003e) {}\n\nconst sample = new Sample()\nconst l1 = sample.$latch(\"foo\", { limit: 2 }, async (h, data) =\u003e {\n    console.log(\"foo:\", data)\n    return Hookable.CONTINUE\n})\nconst l2 = sample.$latch(\"bar\", { pos: \"late\" }, async (h, data) =\u003e {\n    console.log(\"bar: start:\", data)\n    return new Promise((resolve) =\u003e {\n        console.log(\"bar: end:\", data)\n        resolve(Hookable.FINISH)\n    })\n})\n\nsample.$hook(\"foo\", { arg: \"foo1\" }) // -\u003e foo: { arg: foo1 }\nsample.$hook(\"foo\", { arg: \"foo2\" }) // -\u003e foo: { arg: foo2 }\nsample.$hook(\"foo\", { arg: \"foo3\" }) // -\u003e (none)\nsample.$hook(\"bar\", { arg: 42 })     // -\u003e bar: start: { arg: 42 }, bar: end: { arg: 42 }\n\nl1.unlatch()\nl2.unlatch()\nl3.unlatch()\n```\n\nTrait: *Finalizable*\n-------------------\n\nThe reusable generic trait *Finalizable* allows you to potentially react when a\ntarget class is finalized (disposed by garbage collection). You can observe the\nfinalization event by overriding method `$finalize`. Apply a *Finalizable*\nfor allowing you to take optional action before garbage collection.\n\nNOTICE: internally, the standard mechanism `FinalizationRegistry` is\nused and there is no guarantee that the `$finalize` method is called soon\nafter garbage collection of the target class or even called at all. Hence,\nuse the `$finalize` method just for fully optional memory deallocation\ntasks only, please.\n\n```ts\nimport { derive }      from \"@traits-ts/core\"\nimport { Finalizable } from \"@traits-ts/stdlib\"\n\nclass Sample extends derive(Finalizable) {\n    $finalize () {\n        console.log(\"finalized\")\n    }\n}\n\nconst sample = new Sample()\n```\n\nTrait: *Traceable*\n------------------\n\nThe reusable generic trait *Traceable* allows you to perform\nsimple log-level based logging from within a target class. The\navailable log-levels have to be defined in a string-union type `T` of\n`Traceable\u003cT\u003e` and the corresponding string-array property `$logLevels`\non the target class. The current log-level has to be defined with\nthe string property `$logLevel`. The generated output is by default\nsuppressed, but can be output by defining the function property\n`$logOutput`. The log entries can be generated by the method `$log`.\nApply a *Traceable* for allowing a target class to perform simple\nlogging.\n\n```ts\nimport { derive }    from \"@traits-ts/core\"\nimport { Traceable } from \"@traits-ts/stdlib\"\n\ntype  LogLevelsType   = \"ERROR\" | \"WARNING\" | \"INFO\"\nconst LogLevelsDefine = [ \"ERROR\", \"WARNING\", \"INFO\" ] satisfies LogLevelsType[]\n\nclass Sample extends derive(Traceable\u003cLogLevelsType\u003e) {\n    $logLevels = LogLevelsDefine\n    $logLevel  = \"INFO\" as LogLevelsType\n    $logOutput = (line: string) =\u003e { console.log(line) }\n    action () {\n        this.$log(\"INFO\", \"sample\", { foo: \"bar\", baz: 42 })\n    }\n}\n\nconst sample = new Sample()\n\nsample.action() // -\u003e \u003ctimestamp\u003e [INFO] sample (foo: \"bar\", baz: 42)\n```\n\nTrait: *Serializable*\n---------------------\n\nThe reusable generic trait *Serializable* allows you to export and\nimport the state of a target class. For this, the target class and its\nstate properties have to be decorated with `@serializable`. The class\nand the graph of its dependencies then can be serialized/exported\nwith method `$serialize`. The serialized/exported state can be\ndeserialized/imported again with the static function `$unserialize`.\nApply a *Serializable* for allowing a target class and its dependencies\nto be exported and imported.\n\n```ts\nimport { derive }                     from \"@traits-ts/core\"\nimport { Serializable, serializable } from \"@traits-ts/stdlib\"\n\n@serializable\nclass Sample extends derive(Serializable) {\n    @serializable foo  = true\n    @serializable bar  = 42\n    @serializable baz  = new Set\u003cSample\u003e()\n    @serializable sub?: Sample = undefined\n    constructor (sub?: Sample)  {\n        super()\n        if (sub) {\n            this.sub = sub\n            this.baz.add(sub)\n        }\n    }\n}\nconst sample1 = new Sample()\nconst sample2 = new Sample(sample1)\n\nconst state = sample2.serialize() // -\u003e { ... }\n\nconst sample1New = Sample.$unserialize(state)\nconst sample2New = sample1New.sub\n```\n\nHistory\n-------\n\nThe **@traits-ts/stdlib** library was developed in February 2025 by Dr.\nRalf S. Engelschall. It is heavily inspired by the necessary base class\nfunctionalities which Dr. Ralf S. Engelschall had to develop over the\nyears in various projects.\n\nSupport\n-------\n\nThe work on this Open Source Software was financially supported by the\ngerman non-profit organisation *SEA Software Engineering Academy gGmbH*.\n\nLicense\n-------\n\nCopyright \u0026copy; 2025 Dr. Ralf S. Engelschall (http://engelschall.com/)\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftraits-ts%2Fstdlib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftraits-ts%2Fstdlib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftraits-ts%2Fstdlib/lists"}