Exporting a single value using both default and named exports simultaneously (Circular Dependency)

Recently, I was involved in a TypeScript project that utilized passport-auth0. To ensure proper typing, I added the DefinitelyTyped declaration file for @types/passport-auth0.

When importing the Strategy as a named import from passport-auth0, everything functioned smoothly (with "esModuleInterop": true set in my tsconfig):

import {Strategy} from 'passport-auth0';

However, the Strategy is also exported as a default export. According to the Readme instructions, it should be possible to import it like this:

import Strategy from 'passport-auth0';

Unfortunately, this approach did not work seamlessly with @types/passport-auth0. The error message I encountered was:

Type 'typeof import("/home/vsts/work/1/s/types/passport-auth0/index")' has no construct signatures.

My goal now is to rectify these type definitions.

Answer №1

My quest began with a desire to solve a problem faced by others, leading me down a complex path of attempting to export and import a value both as a default export and a named export (with valuable insights from @nathan-shively-sanders).

The resolution I reached can be found at https://github.com/DefinitelyTyped/DefinitelyTyped/pull/42315.

The initial type definitions I worked with had the following structure:

//
// The class intended for dual export/import as:
//
// - A named export (already functional due to `export class`)
// - A default export (initially malfunctioning)
//
export class Strategy extends passport.Strategy { /* ... */ }

export interface Profile extends passport.Profile { /* ... */ }
export interface AuthenticateOptions extends passport.AuthenticateOptions { /* ... */ }
export interface StrategyOption { /* ... */ }
export interface StrategyOptionWithRequest extends StrategyOption { /* ... */ }
export interface ExtraVerificationParams { /* ... */ }
export type VerifyFunction = ( /* ... */ ) => void;
export type VerifyFunctionWithRequest = ( /* ... */ ) => void;

To resolve this issue, I had to take several steps:

  1. Rename the class from Strategy to StrategyInternal to manage circular references during export import ...
  2. Change the export before the class to declare
  3. Declare a namespace using the new name StrategyInternal at the bottom of the file (referred to as Namespace Merging)
  4. Move all other interfaces and types to the namespace, removing the export declarations
  5. Update internal references within the class to use fully qualified names like StrategyInternal.VerifyFunction
  6. Utilize export import within the namespace to enable named exports
  7. Set the default export with export = StrategyInternal at the end of the file

The finalized solution summary is as follows:

declare class StrategyInternal extends passport.Strategy {
    // Updated references to external types and interfaces
    // For example, changing `VerifyFunction` to `StrategyInternal.VerifyFunction`
}

declare namespace StrategyInternal {
    interface Profile extends passport.Profile { /* ... */ }
    interface AuthenticateOptions extends passport.AuthenticateOptions { /* ... */ }
    interface StrategyOption { /* ... */ }
    interface StrategyOptionWithRequest extends StrategyOption { /* ... */ }
    interface ExtraVerificationParams { /* ... */ }
    type VerifyFunction = ( /* ... */ ) => void;
    type VerifyFunctionWithRequest = ( /* ... */ ) => void;

    // NOTE: not applicable for `export import` statements
    // tslint:disable-next-line:strict-export-declare-modifiers
    export import Strategy = StrategyInternal;
}

export = StrategyInternal;

I'm sharing these details in hopes that it may serve as a solution, particularly because it successfully passes tests and accommodates various styles of ESM imports (when using "esModuleInterop": true in tsconfig):

import {Strategy} from 'passport-auth0';

...or...

import Strategy from 'passport-auth0';

If you are not employing ES Modules interop, these alternative import styles are also supported:

import Strategy = require('passport-auth0');

...or...

import {Strategy} = require('passport-auth0');

Furthermore, in CommonJS written in JavaScript:

const Strategy = require('passport-auth0');

...or...

const {Strategy} = require('passport-auth0');

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

When working with Mongoose and TypeScript, encountering the 'connect' error from mongoose can be frustrating and disruptive to your

After attempting to start the server, an error message is displayed: this.mongo.connect('mongodb://localhost:27017/tsnode', { ^ TypeError: Cannot read property 'connect' of undefined import express from 'express&ap ...

In production mode, ExpressJs dispatches the stack efficiently

Before going live, I want to test production simulation with the following setup: package.json "start": "cross-env NODE_ENV=production node dist/index.js", index.ts console.log(process.env.NODE_ENV) // prints "production" ro ...

learning how to transfer a value between two different components in React

I have 2 components. First: component.ts @Component({ selector: "ns-app", templateUrl: "app.component.html", }) export class AppComponent implements OnInit { myid: any; myappurl: any; constructor(private router: Router, private auth: ...

Does it follow standard practice for Array.filter to have the capability to also perform mapping on an array of objects?

While experimenting with Array.filter, I made an interesting discovery. By forgetting to include an equality check, my array was unexpectedly mapped instead of filtered. Here is the code snippet that led to this result: const x = [{ name: 'user' ...

I encountered an error with Firebase when attempting to run functions on my local machine

Encountering a Firebase error when running the function locally using emulator in CLI $ firebase emulators:start --only functions Initiating emulators: ["functions"] functions: Using node@8 from host. functions: Emulator started at http://localhost:50 ...

Is it possible to implement a cast operator in Typescript?

After using JSWEET to transpile a large Java project, I noticed that it changed types such as Enumeration<Object> directly to Enumeration<any> in TypeScript. Previously in the Java environment, it was possible to assign an array Object[] to an ...

Using TypeScript with Vue to Retrieve Information from a Form

Currently, I am attempting to retrieve data from a form in Vue using TypeScript. However, when declaring the data that I intend to use with this form, it seems to be posted on the fields as shown in this screenshot: message getting posted. I am unsure ho ...

Check if a form field's value is lower than another in Angular reactive forms

In the form, I have a field called LDC along with two other fields named limit1 and limit2. My goal is to display an error message if either limit1 or limit2 exceeds the value of LDC, or if the sum of limit1 and limit2 surpasses LDC. I attempted to creat ...

Dealing with observable errors in Angular 2 beta.12 and RxJS 5 beta.3

Greetings, Currently, I am working with Angular2 beta 12 within VS2015. Upon updating from rxjs version 5.0.0-beta.2 to beta.3, I started encountering several exceptions primarily related to promises. For instance: The property map is not present in th ...

Broadcasting events across the entire system

I'm trying to accomplish something specific in Angular2 - emitting a custom event globally and having multiple components listen to it, not just following the parent-child pattern. Within my event source component, I have: export class EventSourceCo ...

Error message "After the upgrade to Angular 15, the property 'selectedIndex' is not recognized in the type 'AppComponent'."

My Ionic 6 app with capacitor has been updated in the package.json file. These are the changes: "dependencies": { "@angular/common": "^15.1.0", "@angular/core": "^15.1.0", "@angular/forms": "^15.1.0", "@angular/platform-browser": "^15.1. ...

Implementing data type validation for the state variable in a React Functional component

I recently started using React Functional components and I have a question about validating and preventing specific state updates with incorrect data types... Here is the hook I am using: const [apiData, setApiData] = useState({ idProjectHeader: 0, ...

Issue encountered while attempting to remove a post from my Next.js application utilizing Prisma and Zod

Currently, I'm immersed in a Next.js project where the main goal is to eliminate a post by its unique id. To carry out this task efficiently, I make use of Prisma as my ORM and Zod for data validation. The crux of the operation involves the client-sid ...

When setting up a list in TypeScript, it does not verify the type of each element during initialization

In TypeScript, the code snippet below does not generate any error or warning, even though the 1st element does not adhere to the IFileStatus interface: interface IFileStatus { a: string; b: number; } let statuses: IFileStatus[] = [ { ...

In Angular, you can easily modify and refresh an array item that is sourced from a JSON file by following these steps

Currently, I am working on implementing an edit functionality that will update the object by adding new data and deleting the old data upon updating. Specifically, I am focusing on editing and updating only the comments$. Although I am able to retrieve th ...

Using Typescript and webpack to detect variables that are defined in the browser but not in Node environment

My goal is to create a package that can be used on both servers and clients with minimal modifications required. Some libraries are available in Node but not in a browser, while others are accessible in a browser but not in Node. For instance, when utili ...

Error encountered while waiting for Angular to finish loading in Protractor: ScriptTimeoutError - Task: Protractor.waitForAngular()

Yesterday went smoothly, but today after updating to pull all commits from svn, everything stopped working. Every time I run a test, I encounter this error: ScriptTimeoutError: script timeout And: From: Task: Protractor.waitForAngular() - Locator: By(c ...

Unable to iterate over a 2D array using 'rows' in JavaScript or TypeScript

Imagine I need to generate a 2D array with this specific structure: [0, 1, 1, 1] [1, 0, 0, 0] [1, 0, 0, 0] To achieve this, I first initialized a 2D array with 0 values: function createGrid(m: number, n: number): number { let grid: number[][] = new Ar ...

Can the narrowing of types impact a generic parameter within a TypeScript function?

Is there a way to make TypeScript infer the type of the callback parameter inside the funcAorB function correctly? While TypeScript can deduce the type of the callback parameter when calling funcAorB, it fails to do so within the body of funcAorB. I was ex ...

Creating a randomly generated array within a Reactjs application

Every time a user clicks a button in reactjs, I want to create a random array of a specific size. The code for generating the array looks like this: const generateArray = (arraySize: number): number[] => { return [...Array(arraySize)].map(() => ~~( ...