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

Support resolving types from import specifiers using custom schemes #53038

Open
5 tasks done
rschristian opened this issue Mar 1, 2023 · 3 comments
Open
5 tasks done
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@rschristian
Copy link

Suggestion

I can fully appreciate the complexities in type resolution, so applying more things on top is likely... undesired, but thought I'd present this anyways just in case.

In some environments, especially Rollup, it is common to use custom import schemes (import ... from 'example:...') to denote modules that should use a specialized loader (Webpack before v5 used to similarly recommend 'example!...', but that looks to have gone out of fashion). Unfortunately, if these modules do not share a common interface, it is quite difficult to support this in TypeScript, as, as best as I can tell, it would require generating .d.ts entries for every single module.

This is a type resolution-only issue, the built output should not be altered at all.

🔍 Search Terms

import schema scheme protocol

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Depending on the specifics of supported schemes already (such as node:), perhaps it's possible to allow some method of simply ignoring the scheme? So that example:<anything> resolves to <anything>; node:fs could resolve types from fs, and example:./myModule could resolve from ./myModule. This is likely to introduce issues in the future, however, if Node (or any other equivalent) introduces something that mandates a schema, so probably not viable.

Alternatively, perhaps the paths option could be altered to support this, including some way of using relative specifiers without resolving against baseUrl. This should follow standard relative import semantics, just ignore the scheme. I'm not quite sure what that would look like, though I suppose the following probably isn't breaking, as it is not allowed at the moment?

{
  "compilerOptions": {
    "paths": {
      "example:*": "*"
    }
  }
}

Very much open to ideas/suggestions.

📃 Motivating Example

It will allow for TS to support transparent loaders that have become commonplace in many bundler ecosystems. It can replace a good deal of code gen when dealing with file types that TS can retrieve types from directly.

💻 Use Cases

Use: In an ideal world, I could (maybe alongside some configuration) write import { something } from 'example:./myModule'; and have TS correctly retrieve the types for something from myModule directly (if it can), without needing to create a declaration file/entry. This allows me to specify custom loaders that should be used on these modules without giving up TypeScript support.

Shortcomings: TS is simply not supported whilst doing this at the moment. While you could generate .d.ts files/entries for each module, this is simply not viable in my experience and is way too much overhead. Potential type issues at the module boundary are cheaper than TS appeasement.

Workarounds: None that are viable long-term, in my experience.

@RyanCavanaugh
Copy link
Member

In some environments, especially Rollup, it is common to use custom import schemes

I can't find any mention of "schemes" on the Rollup docs. What kind of values of example are common? Can you provide some links for context? I'm familiar with node:name for importing node built-in modules but haven't seen this syntax used for other things.

@rschristian
Copy link
Author

rschristian commented Mar 2, 2023

I can't find any mention of "schemes" on the Rollup docs.

Sorry, I'm not referring to Rollup itself here, but the ecosystem. Rollup won't even resolve from node_modules out-of-the-box, it's kept rather lightweight (and unopinionated).

However, a few common examples include:

  • asset (or some form of)
    • Used to generate URLs for non-JS assets
    • Example
  • content (or, again, some form of)
    • Used to generate an array of blog post data objects, containing information like title, date, and file path
    • Example
  • omt
    • Used to generate a Web Worker (Off Main Thread)
    • Example

The main similarity is that all of these are used in situations where there are consistent types; a generated URL is always a string, blog posts always have a certain type shape, etc. The only thing stopping one from using this pattern with modules that don't have a consistent typing is the type resolution. To some extent this can be "fixed" with code-gen, which some tools do use, but this can be a bit slow and overbearing.

My particular use case at the moment is implementing an "Islands" loader for Rollup -- basically signaling that certain (JSX) components need to be transformed a certain way. Unfortunately, I have to break the pattern and switch to signaling via file name (foo.island.js) instead of the preferred import protocol/scheme that matches everything else in the project (island:./foo.js). As these are (JSX) components, they certainly could benefit from TS providing hints to the type of props a component takes, but they do not share any common interface.

A more concrete example could look like this:

import { MyIsland, OtherExport, ATypeAliasMaybe } from 'island:./MyIsland';

const App = () => <MyIsland />; // What props does this take? TS won't be able to help here.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Mar 2, 2023
@musjj
Copy link

musjj commented Jun 1, 2023

This would definitely be nice to have, along with the ability to have editor warnings for missing/invalid imports of assets, etc.
Might be relevant:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants