tsx icon indicating copy to clipboard operation
tsx copied to clipboard

Cannot access ambient const enums when run by `tsx` but no problem by `ts-node`

Open WankkoRee opened this issue 2 years ago • 9 comments

Problem

I declare enum in typings like it:

// src/typings/main/index.d.ts

declare const enum Test {
  hello = 'world',
}

and tsconfig.json like it:

{
  "compilerOptions": {
    "typeRoots": ["src/typings"]
  }
}

and then I try to use enums like it:

// src/main.ts

console.log(Test.hello);

then it will be ReferenceError: Test is not defined.

Expected behavior

print world just like if I run it by ts-node.

I run it by ts-node without problem, so I think may it is a bug for tsx ?

ts-node behavior: https://codesandbox.io/p/sandbox/tsx-bug-in-ts-node-r9h985

tsx behavior: https://codesandbox.io/p/sandbox/tsx-bug-rl55dz

because StackBlitz does not support ts-node, I use CodeSandbox.

Minimal reproduction URL

https://codesandbox.io/p/sandbox/tsx-bug-rl55dz

Version

v3.12.6

Node.js version

v16.17.0

Package manager

pnpm

Operating system

Windows

Contributions

  • [ ] I plan to open a pull request for this issue
  • [ ] I plan to make a financial contribution to this project

WankkoRee avatar Sep 24 '23 11:09 WankkoRee

I think it might be because of this: https://github.com/esbuild-kit/tsx#does-it-have-any-limitations

esbuild does not support typeRoots so i cannot use it with tsx, but is there any way to slove it?

WankkoRee avatar Sep 24 '23 11:09 WankkoRee

Same issue. Importing a const enum from a private node module. ts-node works with the declare const enum output but not tsx.

marcghorayeb avatar Oct 27 '23 21:10 marcghorayeb

Same, issue, @marcghorayeb any workaround to this ?

idl-asad avatar Mar 18 '24 07:03 idl-asad

Seems like this is still a problem, I just encountered this.

I have library that have .d.ts with const enum to map string to Enum, just like OP:

// some-lib/index.d.ts
export const enum TestEnum {
    Foo = 'foo',
    Bar = 'bar'
}

export function functionRequiresEnum(param: TestEnum);
export default functionRequiresEnum;

When I use this const enum with tsc compiler, this is the result: Input (TypeScript):

import functionRequiresEnum, { TestEnum } from '../some-lib/index.js'; // This uses .d.ts mentioned above
functionRequiresEnum(TestEnum.Foo);

Output (JavaScript):

import functionRequiresEnum from '../some-lib/index.js';
functionRequiresEnum("foo" /* TestEnum.Foo */);

tsc correctly converts Enum to string, because it is const enum and TestEnum does not actually exists in JavaScript file in first place.

But on other hand, tsx does bad job on it:

import functionRequiresEnum, { TestEnum } from '../some-lib/index.js';
                               ^

SyntaxError: The requested module '../some-lib/index.js' does not provide an export named 'TestEnum'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:134:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:217:5)
    at async ModuleLoader.import (node:internal/modules/esm/loader:323:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:120:12)

Node.js v21.7.2

TestEnum is a const enum and should be expanded before evaluation, which in this case did not.

This is same for namespace imports:

import * as someLib from '../some-lib/index.js';

someLib.functionRequiresEnum(someLib.TestEnum.Foo);
                                              ^


TypeError: Cannot read properties of undefined (reading 'Foo')
    at <anonymous> (/tmp/mre-tsx/src/index.ts:3:47)
    at ModuleJob.run (node:internal/modules/esm/module_job:222:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:323:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:120:12)

Node.js v21.7.2

My best guess is that tsx doesn't currently handles "inline" definitions like const enum does.

I have to use slow tsc compiler for now...

Arch Linux rolling
Linux DESKTOP-CMM2KTE-ARCH 6.8.2-arch2-1 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux
Intel Core i9-9900 (8C16T x86_64)

MeemeeLab avatar Apr 06 '24 05:04 MeemeeLab

As per the Contribution guide, I've hid the comments that aren't productive towards landing a fix.


The ts-node reproduction doesn't work. Can you fix it? More importantly, I'm interested in a TypeScript (tsc) reproduction as that's what tsx aims have parity with.

> demo@ start /workspace
> ts-node --esm src/index.ts

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /workspace/src/index.ts
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:160:9)
    at defaultGetFormat (node:internal/modules/esm/get_format:203:36)
    at defaultLoad (node:internal/modules/esm/load:143:22)
    at async nextLoad (node:internal/modules/esm/hooks:865:22)
    at async nextLoad (node:internal/modules/esm/hooks:865:22)
    at async Hooks.load (node:internal/modules/esm/hooks:448:20)
    at async MessagePort.handleMessage (node:internal/modules/esm/worker:196:18) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
 ELIFECYCLE  Command failed with exit code 1.

privatenumber avatar Apr 08 '24 08:04 privatenumber

Hi @privatenumber, I just published repo that contains minimal reproducible example of this bug: https://github.com/MeemeeLab/tsx-mre-issue-321

Just install dependencies by npm i and use scripts:

  • TypeScript tsc compiler: npm run start-tsc
  • node-ts compiler: npm run start-node-ts
  • TSX compiler: npm run start-tsc

Expected results and actual results are documented in my previous post, which apparently you marked it as off-topic.

MeemeeLab avatar Apr 09 '24 10:04 MeemeeLab

Thanks for the reproduction. Being able to play with the result (instead of reading a description) is extremely helpful.

The limitation is simply because tsx doesn't read .d.ts files. But tsx should support them in these cases, and I'd be happy to accept a PR to look up the adjacent .d.ts file for .js files. I think typeRoots could also be supported too but as a follow up (and with lower priority).


I don't want to get into this as it's off-topic, but I hid your previous comment because the interpretation of the problem was confusing to follow without being able to see the problem. And as per the Contribution guide, discussing workarounds (tsc) isn't exactly productive towards landing a fix within tsx.

privatenumber avatar Apr 09 '24 16:04 privatenumber