npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-ts-resolver

v1.0.0

Published

Node resolver hook allowing `.ts` files to be found when imported with `.js` extensions

Readme

Node TypeScript Resolver

This package enables Node.js to resolve TypeScript files the same way TypeScript does - allowing .ts files to be found when imported with .js extensions. It works in conjunction with modern Node.js versions that support loading TypeScript files natively:

  • Node 22.6.0+: --experimental-strip-types
  • Node 22.7.0+: --experimental-transform-types
  • Node 23.6.0+: Type stripping enabled by default (no flag needed)

It fully replaces the need for tools such as ts-node or tsx, and makes node behave more like bun when it comes to loading TypeScript files.

The Problem

ESM requires full file extensions for module resolution. TypeScript follows the philosophy of never transforming existing valid JavaScript constructs, so it expects .js extensions in imports even when referencing .ts source files.

However, Node's native type handling doesn't resolve .ts files when you import with .js extensions, causing module resolution errors.

One workaround is to enable allowImportingTsExtensions in your tsconfig.json, and have your import statements use .ts. Unfortunately, this means the compiled output JavaScript files will have .ts extensions, which will not work after building (since after building the files will now have .js extensions), unless you then also enable rewriteRelativeImportExtensions to convert them back to .js.

This however requires you to use tsc as the compiler for .ts files, and only works for TypeScript files in your own project. It does not support resolving .ts files imported using absolute paths, path aliases, or from other packages, which is a common use case in monorepos.

Example

Given these files:

// add.ts
export const sum = (a: number, b: number): number => a + b;
// main.ts
import { sum } from './add.js'; // despite .js extension, TypeScript actually resolves this to './add.ts'
console.log(sum(2, 3));
# This fails - Node can't find add.js when add.ts exists
node --experimental-strip-types main.ts

Results in:

node:internal/modules/esm/resolve:257
   throw new ERR_MODULE_NOT_FOUND(
          ^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module './add.js' imported from ./main.ts

Whereas if you use this package, it resolves correctly:

node --experimental-strip-types --import node-ts-resolver/register main.ts

# Results in: 5

Installation

Install the package in your project:

npm install node-ts-resolver

Usage

Basic Usage

Whenever running node, simply add --import node-ts-resolver/strip or --import node-ts-resolver/transform to your command.

For example that supports type stripping only:

node --experimental-strip-types --import node-ts-resolver/strip main.ts

With type transformations (enums, namespaces, etc.):

node --experimental-transform-types --enable-source-maps --import node-ts-resolver/transform main.ts

Note: When using the transform mode, it's recommended to use the --enable-source-maps flag to preserve original source maps for better debugging.

Node.js Version Considerations

Type stripping is enabled by default since Node 23.6.0+, so you can omit the --experimental-strip-types flag:

node --import node-ts-resolver/strip main.ts

Alternative Usage

Instead of the import flag, you can also import the resolver in your entry file:

// entry.ts
import "node-ts-resolver/strip"; // or "node-ts-resolver/transform"
import("./main.js");

Then run with just the required handling flag:

node --experimental-strip-types entry.ts

.js takes precedence

Note that native resolution always takes precedence over TypeScript resolution. If a .js file exists, it will be resolved instead of a .ts file with the same name. This is consistent with how TypeScript resolves modules, ensuring that existing JavaScript files are prioritized.

Monorepo Support

node-ts-resolver enables resolving .ts files in node_modules, making monorepo support possible.

This is achieved by using amaro under the hood, which is Node's internal TypeScript loader, and is responsible for type stripping and transforming. This allows the resolver to handle TypeScript files anywhere in the dependency tree, not just in your local project.

Example

// packages/my-shared-package/src/utils.ts
export function sharedUtil(): string {
  return "Hello from my-shared-package";
}
// packages/app/src/main.ts
import { sharedUtil } from "my-shared-package/src/utils.js"; // Note: .js extension
console.log(sharedUtil());

With node-ts-resolver, this works seamlessly without needing to build the shared package first:

node --experimental-strip-types --import node-ts-resolver/strip packages/app/src/main.ts

Inspiration

This project started off as a fork from node-resolve-ts by Franklin Ross.

It was created to address the limitations of that package, particularly around monorepo support. Additionally, it should be a little bit more performant, as it runs builtin resolution mechanism first, and only falls back to TypeScript resolution if it fails.