1

I have the following code:

import {AsyncLock} from 'async-lock';

but tsc is complaining:

[ts] Module '"my_app/node_modules/@types/async-lock/index"' has no exported member 'AsyncLock'.

but if I look at my_app/node_modules/@types/async-lock/index.d.ts I see the following:

interface AsyncLockDoneCallback {
    (err?: Error, ret?: any): void;
}

interface AsyncLockOptions {
    timeout?: number;
    maxPending?: number;
    domainReentrant?: boolean;
    Promise?: any;
}

declare class AsyncLock {
    constructor(options?: AsyncLockOptions);

    acquire(key: string | string[], fn: (done: AsyncLockDoneCallback) 
=> any, cb: AsyncLockDoneCallback, opts?: AsyncLockOptions): void;
    acquire(key: string | string[], fn: (done: AsyncLockDoneCallback) 
=> any, opts?: AsyncLockOptions): PromiseLike<any>;

    isBusy(): boolean;
}

declare namespace AsyncLock { }

export = AsyncLock;

It very much looks to me as if AsyncLock is being exported here. Where am I going wrong with my import definition?

1 Answer 1

1

Short Answer

When a declaration file exports like this:

export = AsyncLock;

Then we import it in one of these two ways:

import AsyncLock = require("async-lock"); // thank you unional
import * as AsyncLock from "async-lock";

Both support static analysis. (See unional's corrections below in the comments.)

Further Details

From the TypeScript modules documentation:

Both CommonJS and AMD generally have the concept of an exports object which contains all exports from a module.

They also support replacing the exports object with a custom single object. Default exports are meant to act as a replacement for this behavior; however, the two are incompatible. TypeScript supports export = to model the traditional CommonJS and AMD workflow.

What you were trying to use is the more modern style, when a declaration file exports like this:

export { AsyncLock }

In that case, we do import it like this:

import { AsyncLock } from "async-lock";
Sign up to request clarification or add additional context in comments.

7 Comments

Note that NodeJS is going against this, and prefer import x = require('async-lock')
@unional My sense is that using require(...) is deprecated in favor of the new ECMA module system. For instance MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… does not mention require(...), nor does the ECMAScript living standard tc39.github.io/ecma262 Also, the NodeJS docs mark require(...) as deprecated nodejs.org/api/modules.html#modules_require
It is mentioned in github.com/nodejs/node-eps/issues. It's a topic span across multiple issues and you can start from here github.com/Microsoft/TypeScript/issues/16093 and follow the links. The bottom line here is the interop syntax was not defined by tc39 and TS and NodeJS/Babel/SystemJS goes in different ways. We now need to find a way to fix this issue.
Also, the "deprecated" part in nodejs.org is the require.extensions, not require() itself.
Another note that require() will never be on MDN nor ECMAScript living standard because it is part of module loader, not part of the language. We would like to migrate to ESM, but we first need to solve the migration issue from CJS to ESM.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.