Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/samdenty/mix-classes
Seamlessly combine class inheritance with composition, guaranteed to work with any class
https://github.com/samdenty/mix-classes
Last synced: 17 days ago
JSON representation
Seamlessly combine class inheritance with composition, guaranteed to work with any class
- Host: GitHub
- URL: https://github.com/samdenty/mix-classes
- Owner: samdenty
- Created: 2019-05-04T13:05:00.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2019-10-21T22:26:50.000Z (about 5 years ago)
- Last Synced: 2024-11-26T21:15:11.391Z (25 days ago)
- Language: TypeScript
- Homepage:
- Size: 817 KB
- Stars: 7
- Watchers: 4
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# mix-classes
Easily add typescript-safe mixins to JS classes, with support for generics, constructors, overloading and more. Correctly handles `this` for each class, so it'll work with anything.
- Typescript generics
- Pass arguments to mixins, by providing an array of arguments
- Supports `super` calls in overloaded methods
- Use [`instanceof`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/instanceof) to check for mixin classes
- Handles the `this` inside classes, so that they always access their local scope first. No need to worry about name-collisions```ts
import { Mix } from 'mix-classes'class Contactable {
constructor(public email: string, public phone?: string) {}
}
class Nameable {
constructor(public name: string) {}
}
class Website {
constructor(public websiteUrl: string) {}
}class Developer extends Mix(Nameable, Contactable, Website) {
constructor() {
super(['Bob'], ['[email protected]'], ['https://example.com'])
}
}class Company extends Mix(Nameable, Contactable) {
constructor() {
super(['Apple'], ['[email protected]', '18-00'], ['https://apple.com'])
}
}const developer = new Developer()
developer.name
developer.email
developer.websiteUrlconst company = new Company()
company.name
company.email
company.phone
company.websiteUrl
```## Constructor arguments
You can pass custom constructor arguments to each mixin within an array inside the `super` call. The arguments order is dependant on the `mix` array order.
```ts
import { Mix } from 'mix-classes'class Nameable {
constructor(public name: string) {}
}class Ageable {
constructor(public age: number) {}
}class Person extends Mix(Nameable, Ageable) {
constructor() {
super(['Bob'], [50])
// ^ name argument for Nameable
// ^ age argument for Ageable
}
}
```## Overloading
All mixins are seperate classes with different `this` values, meaning you don't need to worry about name collisions.
```ts
import { Mix, getMixin } from 'mix-classes'class A {
variable = 'a'
public a() {
return this.variable
}
}class B {
variable = 'b'
public b() {
return this.variable
}
}class Test extends Mix(A, B) {
constructor() {
super()// The default value is the last mixin specified
console.log(this.variable) // 'b'// Use getMixin to get overloaded properties
console.log(getMixin(this, A).variable) // 'a'// Mixins retain access to their local variables
this.a() // 'a'
this.b() // 'b'
}
}const test = new Test()
```## Typescript generics
Typescript generics are supported, but it requires using Typescript's declaration merging.
To use them, simply wrap the class that you want to pass generics to in `Generic()`, and then add an interface with the same name as the class you want it in.
Before:
```ts
import { Mix } from 'mix-classes'class MyClass extends Mix(
User,
Nameable,
Ageable
) {}
```After:
```ts
import { Generic, Mix } from 'mix-classes'// Move all generic type signatures to the interface
// including default values.
interface MyClass extends User<'bob'> {}class MyClass extends Mix(Generic(User), Nameable, Ageable) {}
``````ts
import { Mix, Generic } from 'mix-classes'class B {}
class Role {
constructor(public type: Type) {}
}class User {
constructor(public username: Username) {}
}interface Admin extends User<'bob'>, Role<'admin'> {}
class Admin extends Mix(Generic(User), Generic(Role), B) {
constructor() {
super(['bob'], ['admin'])
}
}const test = new Admin()
test.username // type 'bob'
```