What is the best way to define a TypeScript type for a default export JavaScript class static factory method?

I'm in the process of developing a vanilla JavaScript library and have a JS class that looks like this:

class MyClass {
  static create() {
    return new MyClass();
  }

  doOneThing() {
    // ...
    return this; 
  }

  doOtherThing() {
    // ...
    return this; 
  }
}

module.exports = MyClass;

This allows for a DSL-like syntax to be used:

MyClass
  .create()
  .doOneThing()
  .doOtherThing();

I am now trying to add a d.ts typings file for TypeScript developers who may want to use it. This is what I have so far:

export interface MyClassInstance {
    doOneThing(): MyClassInstance;
    doOtherThing(): MyClassInstance;
}

export interface MyClassStatic {
    create(): MyClassInstance;
}

declare const MyClass: MyClassStatic;
export default MyClass;

With TypeScript, the import statement would look like this:

import MyClass from "./src/MyClass";

However, when working in a JavaScript file, my IDE suggests using:

MyClass.default.create();

I have considered wrapping my class in an object for consistent behavior between TS and JS but prefer not to go with that approach.

So my question is, is there another way to achieve both static method and default export working seamlessly in both JS and TS?


UPDATE 1

I have discovered that I can declare a class instead of an interface in my .d.ts file like this:

declare class MyClass {
    static create(): MyClass;
    doOneThing(): this;
    doOtherThing(): this;
}
export default MyClass;

Both JS and TS seem to work well with this approach, although I am still evaluating if it's best practice.


UPDATE 2

It appears that this is the most suitable solution. I also reviewed the DefinitelyTyped repo and noticed that some modules use the class declaration in their typings, so I believe this approach is acceptable.

Answer №1

Be sure to review the section on export = and import = require():

// update to
export = MyClass;

If this isn't necessary for the specific exercise, consider writing in TypeScript and using --declaration when compiling to automatically generate the .d.ts file.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Proper method for inserting a value into a string array in a React application using TypeScript

How can I properly add elements to a string array in react? I encountered an error message: Type '(string | string[])[]' is not assignable to type 'string[]' You can view the code on this playground link : Here Could it be that I&apos ...

Error occurs when ng-include is used within a ui-view

When implementing Angular.js in my application, I encountered an error when using ng-include within ui-view. The error message reads: Error: e is null .after/<@http://localhost/vb-asli/js/angular.min.js:152:228 r@http://localhost/vb-asli/js/angular.min ...

Observable task queuing

Here's the scenario: In my application, the user can tap a button to trigger a task that takes 2 seconds to complete. I want to set up a queue to run these tasks one after another, in sequence. I am working with Ionic 3 and TypeScript. What would be ...

retrieveStyle() rooted framework Category

I have implemented a customized Native Base style theme following the instructions in this link. Imports: import material from './native-base-theme/variables/material'; import getTheme from './native-base-theme/components'; return ( ...

Stubbing out a module's function with Sinon

Let's envision a scenario where there is a file present: // app.js const connection = require('./connection.js') module.exports = function (...args) { return async function (req, res, next) { // code implementation ... const ...

Tips for integrating error management in Angular with RXJS

Implementing error handling in the use case method by using subscriptions is my goal. When an error occurs in the adapter, the handling should be done in the use case. However, in the code snippet provided below, the catch block does not seem to work pro ...

Exploring scroll functionality with Webdriver.io v4

My code is designed to log into the beta version of mediawiki, navigate to the Preferences page, and attempt to click on a button located at the bottom of the page. In order to achieve this, I am utilizing the scroll() function because using only .click() ...

Every time I attempt to use the reset() function in typescript, I encounter a type error that prevents its

I am encountering a type error message that reads: 9: Property 'reset' does not exist on type 'EventTarget'. 18 | }); 19 | 20 | e.target.reset() | ^^^^^ 21 | } Below is the relevant code snippet: const hand ...

Angular 2 forms, popping the chosen item in the `<select>` element

Check out the FormBuilder: let valuesArray = fb.array([ fb.group({ name: 'one' }), fb.group({ name: 'two' }), fb.group({ name: 'three' }), fb.group({ name: 'four' }) ]); this.for ...

When using jQuery AJAX, the script is returning blank values

Facing a frustrating issue here. I'm sending an AJAX request to a PHP file, but when I check Chrome Network Tools, it doesn't return any JSON data. However, when I try posting the same data using POSTMAN in Chrome, it returns correctly. Also, if ...

What method is most effective for combining two JSON files in Angular?

My data includes a json file with a product list that looks like this: [{"id":76, "name":"A", "description":"abc", "price":199, "imageUrl":"image.jpg", "productCategory":[{ "categoryId":5, "category":null },{ "categoryId":6, " ...

What could be causing the jQuery code to not function properly when the left or right keys are pressed during mousedown?

Explanation of HTML code: <div class="wrap"> </div> Description of JavaScript code: $(document).ready(function() { $("body").mousedown(function(event) { switch (event.which) { case 1: alert('hel ...

Exploring A-Frame VR: Understanding the Distinction between Cursor and Raycaster

I'm in the process of developing a WebVR project that allows users to interact with the environment by 'clicking' on entities. Can you explain the distinction between using the cursor fuse attribute and the raycaster for interaction? ...

An unexpected stats.js error occurred while attempting to apply custom styles to the map in AngularGoogleMaps,

My experience with Angular Google Maps has been mostly positive, except for one issue that I have encountered. When attempting to add styles to the map using the styles input attribute, I encounter an error: js?v=quarterly&callback=agmLazyMapsAPILoad ...

``Please note that the Sinon spy.called method is currently not

Context In my setup, a small server receives data from a machine. Each time a message is received, a function in a dispatcher object is called, which simply logs everything it receives to the console. Issue While I can see the logs in the console, Sinon ...

Techniques for extracting a specific section of a string in Javascript

On another web page, I am extracting a specific string. My goal is to store that string in a variable after a specific point. For example: #stringexample var variable; I need the variable to only include "stringexample" without the # symbol. How can I a ...

Creating dynamic dropdown menus in React JS through conditions

I'm currently working on a Dnd Character Sheet builder and I need to implement 6 dropdowns for the main stats. Each dropdown should have options from an array of values [8,10,12,13,14,15]. However, once a number is selected in one dropdown, it should ...

The issue with running commands in parallel using npm remains unresolved

Within my project folder, I have a package.json file located at the root directory. This JSON file contains separate client and server folders. In the main package.json file, I have defined the following scripts: "scripts": { "server&quo ...

JavaScript - retrieve only the domain from the document.referrer

I am trying to extract only the domain from referrer URLs. Two examples of referrer URLs I encounter frequently are http://www.davidj.com/pages/flyer.asp and http://www.ronniej.com/linkdes.com/?adv=267&loc=897 Whenever I come across URLs like the ones ...

Angular 2 - Dragula for ng2

<div *ngFor="let col of columns"> ... <div [dragula]="'tickets-list'" [dragulaModel]="col.tickets" (drop)="onDrop($event, col)"> <ul> <li *ngFor="let ticket of col.tickets"> {{ ticket }} </li ...