Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I dynamically export Class methods as standalone functions in TypeScript?

I am rewriting an old NPM module in TypeScript, and I ran into an interesting problem.

The module, in its current state, looks like this -

1.1 my-module.js

export function init(options) {
    //initialize module
}

export function doStuff(params) {
    //do stuff with options and other things
}

1.2 example.js

var m = require('my-module');
m.init({thing: 'doodad'});
m.doStuff('bwoah');

I'm rewriting this in TS (targeting ES6), and plan to write the module as a class that can take a constructor (in lieu of init()), letting me write nice things like -

1.3 example-new.js

import {Thing} from 'my-module';
const aThing1 = new Thing({thing: 'doodad'});
const aThing2 = new Thing();
aThing2.init({thing: 'doodad'});
aThing1.doStuff('bwoah');
aThing2.doStuff('bwoah');
// If I can do at least one of aThing1 or aThing2, I can die a happy man.

The rewritten TypeScript module looks like this -

1.4 my-module-new.js

class Thing {
    options: Object;
    constructor(options: Object) {
        this.options = options;
    }
    init(options: Object) {
        this.options = options;
        return this;
    }
    doStuff(thingForStuff: string) {
        // ...
    }
}

What I'd like to achieve

I want to maintain full backwards-compatibility with the old API as well. So ideally, I should be able to do both 1.2 and 1.3.

What I've tried so far

  1. exporting the Thing class; this lets me do 1.3, but not 1.2.
  2. exporting a singleton, with export default new Thing(); this lets me do 1.3, but not 1.2.
  3. Writing something like this -

    export class Thing {
        options: Object;
        constructor(options: Object) {
            this.options = options;
        }
        init(options: Object) {
            this.options = options;
            return this;
        }
        doStuff(thingForStuff: string) {
            // ...
        }
    }
    
    const singleThing = new Thing();
    
    export function init(options) {
       return singleThing.init(options);
    }
    
    export function doStuff(string) {
       return singleThing.doStuff(string);
    }
    

This works well with both 1.2 and 1.3 - but this seems tedious to basically duplicate each function.

Surely there must be a more elegant way of doing this?

like image 327
GPX Avatar asked Sep 18 '25 18:09

GPX


1 Answers

Yes, we can! © In "Thing" file combine default export and export:

export class Thing {
    init() { }
}

export default new Thing();
like image 109
Sergey Yarotskiy Avatar answered Sep 21 '25 08:09

Sergey Yarotskiy