Skip to content

Instantly share code, notes, and snippets.

@antongolub
Last active January 19, 2020 19:07
Show Gist options
  • Save antongolub/4accfec9f03774a5fb5ae30a5319259a to your computer and use it in GitHub Desktop.
Save antongolub/4accfec9f03774a5fb5ae30a5319259a to your computer and use it in GitHub Desktop.
Apply mixins as a sub-class
export const applyMixinsFixed = <T extends IConstructable, U extends IConstructable[]>(target: T, ...mixins: U) => {
class Mixed extends target {
constructor(...args: any[]) {
super(...args)
mergeDescriptors(this, ...mixins.map(M => new M(...args)))
}
}
mergeProto(Mixed, target, ...mixins)
mergeDescriptors(Mixed, target, ...mixins)
return Mixed
}
export const mergeProto = (target: any, ...mixins: any[]) => mergeDescriptors(target.prototype, ...mixins.map(a => a.prototype))
export const mergeDescriptors = <T, U extends any[]>(target: T, ...mixins: U): T & UnionToIntersection<U[number]> =>
mixins.reduce((m, v) => {
Object.getOwnPropertyNames(v).forEach(name => {
// TODO exclude other fields
if (typeof v === 'function' && (name === 'length' || name === 'name')) {
return
}
if (name === 'prototype' || name === 'constructor') {
return
}
Object.defineProperty(
m,
name,
Object.getOwnPropertyDescriptor(v, name) as PropertyDescriptor,
)
})
return m
}, target)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment