简体   繁体   中英

Typescript interface definition of dynamically generated class

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();

Playground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM