{"id":13683404,"url":"https://github.com/michaelolof/typescript-mix","last_synced_at":"2026-02-03T10:37:14.579Z","repository":{"id":41583718,"uuid":"109483166","full_name":"michaelolof/typescript-mix","owner":"michaelolof","description":"A tweaked implementation of TypeScript's default applyMixins(...) idea using ES7 decorators","archived":false,"fork":false,"pushed_at":"2019-09-23T20:58:38.000Z","size":888,"stargazers_count":87,"open_issues_count":8,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-01T10:00:07.709Z","etag":null,"topics":["mixins","traits-decorator","typescript","typescript-mixins"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/typescript-mix","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/michaelolof.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-04T09:42:46.000Z","updated_at":"2025-09-10T07:39:15.000Z","dependencies_parsed_at":"2022-07-15T15:30:48.046Z","dependency_job_id":null,"html_url":"https://github.com/michaelolof/typescript-mix","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/michaelolof/typescript-mix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelolof%2Ftypescript-mix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelolof%2Ftypescript-mix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelolof%2Ftypescript-mix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelolof%2Ftypescript-mix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/michaelolof","download_url":"https://codeload.github.com/michaelolof/typescript-mix/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelolof%2Ftypescript-mix/sbom","scorecard":{"id":641426,"data":{"date":"2025-08-11","repo":{"name":"github.com/michaelolof/typescript-mix","commit":"e19a36b4473cdab889cbb66b17cc7ef64b38c065"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T10:52:59.890Z","repository_id":41583718,"created_at":"2025-08-21T10:52:59.890Z","updated_at":"2025-08-21T10:52:59.890Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29041777,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T10:09:22.136Z","status":"ssl_error","status_checked_at":"2026-02-03T10:09:16.814Z","response_time":96,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["mixins","traits-decorator","typescript","typescript-mixins"],"created_at":"2024-08-02T13:02:10.088Z","updated_at":"2026-02-03T10:37:14.557Z","avatar_url":"https://github.com/michaelolof.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# TypeScript Mix\n\nA tweaked implementation of TypeScript's default applyMixins(...) idea using ES7 decorators. \n\n## Breaking Changes from Version 3.0.0 upwards\n* New decorator @delegate introduced\n* Changes made in how multiple mixins implementing the same method are mixed\n\nSee [Breaking Changes Explained](#breaking-changes-explained)\n\n## Dependencies\n   * TypeScript\n   * ES7 Decorators\n \n\n## Installation\n```\nnpm install --save typescript-mix\n```\n\n## Features\n  * Properties in a mixin are not mixed into the client. They are ignored. See [TypeScript Mix — Yet Another Mixin Library](https://medium.com/@michaelolof/typescript-mix-yet-another-mixin-library-29c7a349b47d) for a detailed explanation on why. \n  * Classes and Object Literals can be used as mixins.\n\n\n## Goals\n\n   * Ensure programming to an interface and not just only multiple implementations.\n\n   * Create simple mixins that implement that interface\n\n   * Provide an intuitive and readable way of using such mixins in a concrete class.\n\n\n\n## Why I wrote yet another Mixin Library.\n\nThe mixin pattern is somewhat a popular pattern amongst JavaScript/TypeScript devs as it gives the power of \"mixin in\" additional functionality to a class. The official way of using mixins as declared by Microsoft in TypeScript can be really verbose to downright unreadable.\n\n\n## How to use\n\n### The 'use' decorator\n\n#### Program to an interface.\n\n```\ninterface Buyer {\n  price: number\n  buy(): void\n  negotiate(): void\n}\n```\n\nCreate a reusable implementation for that interface and that interface alone (Mixin)\n\n```\nconst Buyer: Buyer = {\n  price: undefined,\n  buy() {\n    console.log(\"buying items at #\", this.price );\n  },\n  negotitate(price: number) {\n    console.log(\"currently negotiating...\");\n    this.price = price;\n  },\n}\n```\n\nDefine another mixin this time using a Class declaration.\n```\nclass Transportable {\n  distance:number;\n  transport() {\n    console.log(`moved ${this.distance}km.`);\n  }\n}\n```\n\n\nDefine a concrete class that utilizes the defined mixins.\n\n```\nimport use from \"typescript-mix\";\n\nclass Shopperholic {\n  @use( Buyer, Transportable ) this\n  \n  price = 2000;\n  distance = 140;\n}\n\nconst shopper = new Shopperholic();\nshopper.buy() // buying items at #2000\nshopper.negotiate(500) // currently negotiating...\nshopper.price // 500\nshopper.transport() // moved 140km\n```\n\n#### What about intellisense support?\nWe trick typescript by using the inbuilt interface inheritance and declaration merging ability.\n```\ninterface Shopperholic extends Buyer, Transportable {}\n\nclass Shopperholic {\n  @use( Buyer, Transportable ) this\n  \n  price = 2000;\n  distance = 140;\n}\n```\n\n### The 'delegate' decorator\nThe delegate decorator is useful when we want specific functionality mixed into the client.\n```\nclass OtherClass {\n  simpleMethod() {\n    console.log(\"This method has no dependencies\");\n  }\n}\n\nfunction workItOut() {\n  console.log(\"I am working it out.\")\n}\n\nclass MyClass {\n  @delegate( OtherClass.prototype.simpleMethod )\n  simpleMethod:() =\u003e void\n\n  @delegate( workItOut ) workItOut:() =\u003e void\n}\n\nconst cls = new MyClass();\ncls.simpleMethod() // This method has no dependencies\ncls.workItOut() // I am working it out\n```\n\n\n## Things to note about this library?\n* using the 'use' decorator mutates the class prototype. This doesn't depend on inheritance (But if you use mixins correctly, you should be fine)\n\n* mixins don't override already declared methods or fields in the concrete class using them.\n\n* Mixins take precedence over a super class. i.e. they would override any field or method from a super class with the same name.\n\n* instance variables/fields/properties can be declared or even initialized in your mixins. This is necessary if you're defining methods that depend on object or class properties but these properties won't be mixed-in to the base class so you have to redefine those properties in the base class using the mixin.\n\n\n## Advantages\n   * The Library is non-obtrusive. Inheritance still works, (multiple inheritance still works ('Real Mixins Style')).\n\n## \u003ca name=\"breaking-changes-explained\"\u003eBreaking Changes Explained\u003c/a\u003e\n### The delegate decorator\nThe addition of the delegate decorator now means module is imported as:\n```\nimport { use, delegate } from \"typescript-mix\"\n```\n\n### Multiple Mixins with the same method.\nConsider the following piece of code.\n![alt text](https://github.com/michaelolof/typescript-mix/blob/master/imgs/2018-05-30%2021_32_46-Preview%20README.md%20-%20typescript-mix%20-%20Visual%20Studio%20Code.png?raw=true)\n\nCleint One uses two mixins that contain the same method mixIt(). How do we resolve this? Which method gets picked?.\nOne advantage of extending interfaces as we've defined above is that we're essentially telling TypeScript to mix-in the two mixin interfaces into the ClientOne interface. So how does TypeScript resolve this?\n\n![alt text](https://github.com/michaelolof/typescript-mix/blob/master/imgs/2018-05-30%2021_49_13-final.ts%20-%20typescript-mix%20-%20Visual%20Studio%20Code.png?raw=true)\n\nNotice that TypeScript's intellisense calls MixinOne.mixIt() method. Therefore to be consistent with TypeScript and avoid confusion the '@use' decorator also implements MixinOne.mixIt() method.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelolof%2Ftypescript-mix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichaelolof%2Ftypescript-mix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelolof%2Ftypescript-mix/lists"}