Skip to content
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

Typescript error: this expression is not constructable #63

Open
AxelTerizaki opened this issue Mar 27, 2023 · 11 comments
Open

Typescript error: this expression is not constructable #63

AxelTerizaki opened this issue Mar 27, 2023 · 11 comments
Assignees
Labels
Bug Something isn't working

Comments

@AxelTerizaki
Copy link
Contributor

AxelTerizaki commented Mar 27, 2023

Description

When using moduleResolution: node16 or nodenext in tsconfig.json, building with a call to the module causes the following error :

$ tsc
services/animeList.ts:12:21 - error TS2351: This expression is not constructable.
  Type 'typeof import("C:/xxx/karaokemugen-server/node_modules/anilist-node/lib/types/index")' has no construct signatures.

12 const anilist = new Anilist();
                       ~~~~~~~

Steps to Reproduce

  1. Create a new typescript project with moduleResolution: node16
  2. Try to spawn a new instance of Anilist in your code as described in the README.

Environment
Node.js Version: 18.12.1 (tyepscript version 5.0.2)
AniList-Node Version: 1.13.1

Thanks for looking into this! This would help a lot with a project I'm trying to keep up-to-date.

@AxelTerizaki AxelTerizaki added the Bug Something isn't working label Mar 27, 2023
@AxelTerizaki
Copy link
Contributor Author

I tried a few things to fix this from my own code like

import { default as Anilist } from 'anilist-node';

But it didn't work.

I had to edit the module itself to make it work. I'll offer a PR.

@AxelTerizaki
Copy link
Contributor Author

I actually wanted to suggest a PR but I'm not sure if what I did was the right way to do it as it introduces a breaking change.

Basically, declare class Anilist was replaced with export class Anilist and I then imported with import { Anilist } from 'anilist-node'

For some reason, with node16 moduleResolution, the default export is not seen as constructable.

@AurelicButter
Copy link
Owner

Can you provide more information about this with your TSConfig and/or snippet of code with the AniList import? I have been unsuccessful trying to replicate the issue.

Using the moduleResolution key, I've gotten import AniList from "anilist-node" (as in the documentation), import { default as Anilist } from "anilist-node" (from your second comment), and import { Anilist } from "anilist-node" (from third comment) all to work with this code without changing the typings.

import Anilist from "anilist-node";

const anilist = new Anilist();

anilist.genres().then(data => { console.log(data); });

For additional reference, this is my TSConfig file that I used for it. I tried both es2017 and es2022 with no luck.

{
	"compilerOptions": {
		"outDir": "./build",
		"allowJs": true,
		"target": "es2017",
		"moduleResolution": "node16",
		"module": "commonjs",
		"esModuleInterop": true,
	},
	"include": ["./src/**/*"]
}

@AxelTerizaki
Copy link
Contributor Author

Thanks for the quick reply!

Here's the tsconfig.json for my project :

{
	"compilerOptions": {
		"target": "ESNext",
		"module": "es2022",
		// Search under node_modules for non-relative imports.
		"moduleResolution": "node16",
		// Process & infer types from .js files.
		"allowJs": false,
		// Don't emit; allow esbuild to transform files.
		"noEmit": true,
		// Enable strictest settings like strictNullChecks & noImplicitAny.
		// true is better but requires a global refactoring.
		"strict": false,
		// Disallow features that require cross-file information for emit.
		"isolatedModules": false,
		// Import non-ES modules as default imports.
		"esModuleInterop": true,
		// Import constants from JSON (locales).
		"resolveJsonModule": true,
		"sourceMap": true,
		"inlineSources": true,
		"sourceRoot": "/",
        "outDir": "dist/",
        "pretty": true,
		"removeComments": true,
		"downlevelIteration": true,
		"noUnusedParameters": true,
		"noUnusedLocals": true
	},
	"include": [
		"src"
    ]
}

@AxelTerizaki
Copy link
Contributor Author

Note : I also have type: module in my package.json. A friend looked into this and realized it might trigger the issue. However, not sure how to fix this on my side... I have other ES modules I use withotu any issues though.

@AurelicButter
Copy link
Owner

Note : I also have type: module in my package.json.

Yep, this is the issue. Added that one line in my package.json with my TSConfig and got the error.

From what I found, it's the combination of type: module in your package.json and moduleResolution: node16 in your TSConfig that is causing an issue. Both node16 and nodenext values for moduleResolution returned the error which leads me to suggest that it's some legacy JavaScript that doesn't want to play nice (some of this code is years old as we speak). However, I got it to function with moduleResolution: node so this might be worth a try on your side to see if that's a good solution.

@AxelTerizaki
Copy link
Contributor Author

The problem is that I actually did specify node16 because I'm transitionning from the node moduleResolution thing. Some packages like file-type won't work with moduleResolution set to node. Try to add the latest version of file-type to your package.json for example :)

@AurelicButter
Copy link
Owner

Yes, I see it. I think I got a full grasp of what's needed now.

Basically, declare class Anilist was replaced with export class Anilist and I then imported with import { Anilist } from 'anilist-node'

Looping back to this, I think this is the fix that we need to solve it. Since you need moduleResolution: node16, there is nothing on your end that can help alleviate the issue for the time being (minus updating the typings file locally yourself).

If you want to make a PR for this, go for it. I don't view this as a breaking change since:

  1. Only the typing have changed
  2. CommonJS context can still use import AniList from "anilist-node" without issue.

Just following the Contributing guide and it'll be fixed in no time.

@AurelicButter
Copy link
Owner

Closing as #64 fixes this issue.

@AxelTerizaki
Copy link
Contributor Author

Hello again.

Sadly, it actually doesn't work :)

While typescript isn't whining anymore, I should have built and tested it all, because as soon as the code is executed, node complains Anilist isn't constructable, which seems right when you think about it. With the PR I made typings and actual code are not in sync anymore.

I'm sorry about that.

I tried to twist how I called/imported anilist-node but it just would either make typescript complain or node complain on runtime. In the end I gave up and added a ts-expect-error line above new Anilist() and it compiled and worked.

I looked into this with a knowledgeable friend and he thinks that it's an authentic typescript bug that might get fixed later because there's no valid reason why it should believe that Anilist() is not constructable as there's a constructor method, it's a class and all...

Sorry about the PR again ^^ It might be interesting to reopen this until it gets fixed in Typescript as ESM is a rather new feature of typescript itself.

@AurelicButter
Copy link
Owner

While typescript isn't whining anymore, I should have built and tested it all, because as soon as the code is executed, node complains Anilist isn't constructable, which seems right when you think about it.

That is pretty weird. I didn't get that error when I compiled and ran it so I don't know what is happening. I'll reopen this in the meantime. 👍

@AurelicButter AurelicButter reopened this Apr 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants