-
-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"#<Object> is not a constructor" when used with TypeScript's allowSyntheticDefaultImports
& esModuleInterop
#5
Comments
The TypeScript module system is broken unless both of those settings are enabled; they should be enabled in every project, full stop (and tsc init enables them in all new projects too) If typescript’s downleveling is incorrect, you’ll have to file an issue with them - I’d suggest using babel for all transpilation, and only use tsc as a typechecker. |
If there’s something that can change in the types (which i don’t maintain) I’d be happy to review and endorse a PR to DefinitelyTyped. |
I agree with the general comment that Babel should be preferred over Back to the original issue, the typings are correct but the runtime behavior isn't. This is plain JS demonstrating the issue: const allSettled = { default: require("promise.allsettled") };
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
allSettled.default([resolved, rejected]).then(results => {
console.log(results);
}); Output:
|
For anyone needing a quick workaround, here's a TypeScript function emulating the behavior. Note: It's probably not as generic & correct as this lib's implementation but works fine for the use case I have. export function allSettled<T>(iterable: Iterable<Promise<T>>): Promise<PromiseResult<T>[]> {
const arr = Array.from(iterable, item => {
return item
.then(value => ({ status: 'fulfilled', value } as PromiseResolution<T>))
.catch(reason => ({ status: 'rejected', reason } as PromiseRejection<typeof reason>));
});
return Promise.all(arr);
}
// Types are taken from
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1d3c224/types/promise.allsettled/types.d.ts
export interface PromiseResolution<T> {
status: 'fulfilled';
value: T;
}
export interface PromiseRejection<E> {
status: 'rejected';
reason: E;
}
export type PromiseResult<T, E = unknown> = PromiseResolution<T> | PromiseRejection<E>;
export type PromiseTuple<T extends [unknown, ...unknown[]]> = { [P in keyof T]: Promise<T[P]> };
export type PromiseResultTuple<T extends [unknown, ...unknown[]]> = { [P in keyof T]: PromiseResult<T[P]> }; |
hmm, I think i see what you mean. This is due to the behavior here: https://github.com/es-shims/Promise.allSettled/blob/master/index.js#L16 combined with the actual spec behavior for In other words, the downleveling is indeed incorrect, since it should not be calling the default function with a receiver - it should be something like There's no way for me to fix things here without violating the spec; this is indeed a bug in TypeScript's downleveling. |
How about exporting the implementation that doesn't re-bind import { allSettled } from 'promise.allsettled/implementation'; |
That already exists under In other words, it seems like what you want is an implementation that always ignores the receiver and sets it to |
Thanks, that's a good-enough workaround. I'm not sure how to formulate that TypeScript issue, if it's an issue at all as they've been generating the current |
That’s probably just because very few packages have modules that take advantage of this |
Ok, I'm no expert on this but created this TS issue anyway: microsoft/TypeScript#35420. Thank you for all the info, @ljharb. |
As a workaround I was able to call the shim method and then use the |
I fixed this issue by using an import require.
|
Had the same issue and fixed it with using .call() on allSettled function: |
This appears to be fixed in the next version of TypeScript. |
This still throws the same error when used with the last typescript version 4.2.3 import allSettled from "promise.allsettled";
allSettled([Promise.resolve(1), Promise.reject("")]); Results in:
tsconfig: {
"compilerOptions": {
"lib": ["ES2019"],
"module": "commonjs",
"target": "ES2019",
"outDir": "dist",
"sourceMap": true,
"declaration": true,
"experimentalDecorators":true,
"emitDecoratorMetadata": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
} |
@alexandrucancescu yes, because the fix isn't released yet. The next version of TypeScript will fix it. |
It was reverted because of a performance regression: microsoft/TypeScript#35877 (comment) |
Without this change, using vitest with "esm": true for routes config and an @Security guarded endpoint led to an error "... is not a constructor" or infinite running tests. Bug related to es-shims/Promise.allSettled#5 (comment)
Without this change, using vitest with "esm": true for routes config and an @Security guarded endpoint led to an error "... is not a constructor" or infinite running tests. Bug related to es-shims/Promise.allSettled#5 (comment)
I'm hitting trouble when trying to use this library in a TypeScript & Babel project. I installed both the lib and the types as usual:
The standard
require
(as described in README) is not TypeScript-friendly, which is normal:That's why the type tests use this syntax:
However, that's not supported by Babel 7 and transitively by all tools that depend on it. For example, our Jest tests fail with this:
Again, this is quite normal and the common fix is to create this
tsconfig.json
:and use this import syntax:
We use this for several other modules and even with
promise.allsettled
, TypeScript is happy at this point and Jest test pass (thepromise.allsettled
code is executed correctly at runtime!).However, it leads to this error when running the app through plain
node
(or viats-node
):My theory is this: in the
--esModuleInterop
&allowSyntheticDefaultImports
mode, TypeScript transpiles the import to this:Note how it wrapped the module into
default
property, so the usages look like this in the transpiled code:And probably,
promise.allsettled
doesn't like this and throws the#<Object> is not a constructor
error.I didn't dive deep into how the various "binds" in this library work but if there was a way to make it more friendly to that specific TypeScript emit scenario, that would be great.
The text was updated successfully, but these errors were encountered: