Skip to content

Instantly share code, notes, and snippets.

@roshanca
Last active April 21, 2020 14:18
Show Gist options
  • Save roshanca/7cac34a8bfb9e05f0a3f47cf0a06d331 to your computer and use it in GitHub Desktop.
Save roshanca/7cac34a8bfb9e05f0a3f47cf0a06d331 to your computer and use it in GitHub Desktop.
TS mixin decoration
class A {
p1() {
console.log('this is p1')
}
}
class B {
p2() {
console.log('this is p2')
}
}
class C {
p3() {
console.log('this is p3')
}
}
@mixin(A, B, C)
class Child {}
const child = new Child()
child.p3()
child.p1()
child.p2()
// this is p3
// this is p1
// this is p2
class Foo {
protected makeFoo() {
return 'foo'
}
}
class Bar {
protected makeBar() {
return 'bar'
}
}
@mixin(Foo, Bar)
class FooBar {
public makeFoobar() {
return this.makeFoo() + this.makeBar()
}
}
const fooBar = new FooBar()
console.log(fooBar.makeFoobar()) // foobar
/**
* A rigorous type alias for a class.
*/
type Class<CtorArgs extends any[] = any[], InstanceType = {}, StaticType = {}> = {
new (...args: CtorArgs): InstanceType & { [K in keyof StaticType]: StaticType[K] }
}
/**
* Mixin decoration implementation
* @example @mixin(ClassA, ClassB, ClassC)
* class targetClass{}
*/
function mixin(...mixins: Class[]) {
return (targetClass: Class) => {
function copyProperties<T extends U, U extends object>(target: T, source: U): void {
for (const key of Reflect.ownKeys(source)) {
if (key !== 'constructor' && key !== 'prototype' && key !== 'name') {
const desc = Object.getOwnPropertyDescriptor(source, key) as PropertyDescriptor
Object.defineProperty(target, key, desc)
}
}
}
for (const mixin of mixins) {
// 拷贝静态属性
copyProperties(targetClass, mixin)
// 拷贝原型属性
copyProperties(targetClass.prototype, mixin.prototype)
}
// 拦截构造器方法,进行实例属性的拷贝
return new Proxy(targetClass, {
construct(target, args: any) {
const obj = new target(...args)
for (const mixin of mixins) {
copyProperties(obj, new mixin())
}
return obj
}
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment