Skip to content

Import specifiers in --experimental-strip-types #214

Closed
@GeoffreyBooth

Description

@GeoffreyBooth

This is a dedicated thread for the issue of file extensions in import specifiers in TypeScript code. Refs: nodejs/node#53725 (comment), #208 (comment), nodejs/node#53725 (comment), nodejs/node#53725 (comment), among others.

Current proposal: Users write full filenames with extensions in their specifiers, similar to ES module JavaScript: import './file.ts'. Also, .ts extensions are required in require calls, similar to the .cjs extension in CommonJS JavaScript: require('./file.ts').

  • This can be type-checked by tsc via the allowImportingTsExtensions tsconfig.json option.
  • This aligns with ES module JavaScript and Deno.
  • tsc cannot compile such TypeScript files into JavaScript (today) but many other build tools can. However, there’s not necessarily a need to compile TypeScript files into JavaScript when they can be run directly. The only benefit that a build step would provide would be for startup time performance (it would be slightly faster to evaluate JavaScript directly rather than stripping types from TypeScript and then evaluating it) and users concerned about this should arguably be using a full-featured bundler such as Vite rather than a one-to-one transpiler such as tsc.

Extension searching alternative: Users would leave off extensions, similar to CommonJS: import './file'. This is a very common way for TypeScript code to be written today, because most TypeScript code is transpiled down to CommonJS JavaScript where such specifiers are permitted.

  • This can’t be supported in require statements, as it would be a semver-major breaking change.
  • It would mean that we can’t add new file formats in the future without them also being breaking changes.
  • If this is implemented by the same pass that replaces types with whitespace, where the extension is added before the source is evaluated, then we have the same problems introduced by supporting transforms: line and column numbers would shift and we would need to add support for source maps, slowing down execution.
  • If this is implemented in Node’s resolution step, then resolution rules for ES module JavaScript would differ based on whether the importing module was a JavaScript file or a TypeScript file. This would be hard to document and explain, and would be a difficult edge case for userland customization hooks to need to support.

Replace .js alternative: Users would write import '/file.js' to refer to file.ts. This is what tsc recommends for users using tsc as their build tool, as it compiles .ts files to .js files one-to-one and never rewrites import specifiers.

  • This is counterintuitive, as there are no .js files generated as part of running files via strip-types.
  • What if both file.js and file.ts exist? None of the various options (error, load one file or the other) are obviously correct or consistent.
  • Rewriting file.ts to file.ts is arguably something that’s logically handled by the build tool or bundler, as that’s the tool generating the file.js file to which the new import specifier would refer. It’s hard to see how it’s Node’s responsibility to make up for a shortcoming in a TypeScript build tool.
  • If this is implemented in Node’s resolution step, then resolution rules for ES module JavaScript would differ based on whether the importing module was a JavaScript file or a TypeScript file. This would be hard to document and explain, and would be a difficult edge case for userland customization hooks to need to support.

Metadata

Metadata

Assignees

No one assigned

    Labels

    typescriptDiscussions related to TypeScripttypescript-agendaIssue or PRs to be discussed during TypeScript team meeting

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions