I do something quite "un typescripty" thing. I have a function that mixes in all methods starting with '_' of a given base class into another dynamically created class.
And I'm struggling to define the right return type.
Here is an example:
export interface IConstructable<T> {
new(): T;
}
class Foobar {
_method() {
console.log('this method should be copied');
}
private method() {
console.log('this method should not be copied');
}
}
function createHtml (base: IConstructable<unknown>): IConstructable<HTMLElement> {
class Html extends HTMLElement {
constructor(){
super();
}
}
Object.entries(Object.getOwnPropertyDescriptors(base.prototype)).forEach(([name, descriptor]) => {
if (name.startsWith('_') && typeof descriptor.value === 'function') {
Object.defineProperty(Html, name, Object.assign({}, descriptor, {
value(){
// some implementation
}
}))
}
});
return Html;
}
const HTMLFoobar = createHtml(Foobar);
new HTMLFoobar()._method();
// I want at least the following interface automatically generated
//
// interface IHTMLFoobar extends HTMLElement, Foobar {
//
// }
//
// const HTMLFoobar = createHtml(Foobar) as IConstructable<IHTMLFoobar>;
// new HTMLFoobar()._method();
If this isn't possible I would be even fine if this would be done programmatically by changing the *.d.ts
file(s) but is there a project that helps read and modify/transform *.d.ts
files that could help here?
You can use generic type parameter instead of unknown
and type assert that generated class is mix of HTMLElement
and the base:
function createHtml<TBase>(base: IConstructable<TBase>): IConstructable<HTMLElement & TBase> {
class Html extends HTMLElement {
constructor(){
super();
}
}
// ...
return Html as IConstructable<HTMLElement & TBase>;
}
const HTMLFoobar = createHtml(Foobar);
new HTMLFoobar()._method();