Skip to content

Support custom/non-vendor modules for lib #45959

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

Closed
5 tasks done
delucis opened this issue Sep 19, 2021 · 12 comments
Closed
5 tasks done

Support custom/non-vendor modules for lib #45959

delucis opened this issue Sep 19, 2021 · 12 comments

Comments

@delucis
Copy link

delucis commented Sep 19, 2021

Suggestion

🔍 Search Terms

lib custom environment

✅ 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

If I understand correctly, currently the lib option in tsconfig can refer to a list of built-in lib declarations to configure the expected JavaScript environment. #44795 and #45685 (implemented via #45771) seem to partially allow customisation of this by pointing to a node module to override a given lib file, e.g.

tsconfig.json
"lib": "es2015"
package.json
"@typescript/es2015": "npm:some-custom-es2015-lib"

In some environments it would be helpful to be able to provide a non-standard lib file to extend what is available globally.

Would it be possible to support passing these directly to lib and have them resolved via the usual package dependency route? In this case, custom-lib-module would be a node module of the appropriate format.

"lib": ["es2015", "custom-lib-module"]

The additional hurdle beyond the module resolution, which #45771 added, is that this would allow values in lib other than those in the list of values supported currently.

📃 Motivating Example

This change makes supporting custom JavaScript environments easier, by allowing easy sharing and extending of lib configurations.

💻 Use Cases

I write JavaScript for use inside Cycling 74’s Max. This runs scripts in an environment with a significant number of custom global APIs (I guess comparable to how a browser environment extends the base ECMA standard). For lesser used environments like this, it would be unreasonable to expect TypeScript to provide built-in lib definitions (or even be aware of them), but being able to write, share, and consume custom lib modules like this would be really helpful.

Current workarounds include:

  • I guess if Support resolving @typescript/[lib] in node modules  #45771 is released in 4.5, it would be possible to hack around this by squatting on one of the official lib names, adding something like "@typescript/dom": "npm:custom-lib-module", but that seems suboptimal. (But — from a position of supreme ignorance — maybe points to a fairly easy path for implementing this?)

  • Including the custom lib declaration files in tsconfig.include. This has the drawback of forcing use of include, which can complicate some set-ups and is not ideal in tsconfig files that are intended to be shared across projects.

  • Using a triple-slash directive. This requires per-file inclusion, which is much less convenient than a project-level option.

@DanielRosenwasser
Copy link
Member

This can already be controlled with the types field, right?

"types": ["custom-lib-module"]

@delucis
Copy link
Author

delucis commented Sep 23, 2021

This can already be controlled with the types field, right?

That does work too, but using types blocks automatic consumption of @types packages, right? (As per the docs.) For something that would ideally be a shareable config, this might be considered an unexpected side effect: why would using a different environment lib force you to be explicit about including other type packages if you weren’t previously?

custom-lib-module/tsconfig.json
{
  "compilerOptions": {
    "types": ["./types"]
  }
}
consumer/tsconfig.json
{
  "extends": "custom-lib-module/tsconfig.json"
  "compilerOptions": {
    "types": [
      // Now we need to explicitly specify any @types modules installed.
      // But all we really wanted was a lib setup.
    ]
  }
}

@andrewbranch
Copy link
Member

You could just /// <reference types="custom-lib-module" /> in any file included in your project though?

@delucis
Copy link
Author

delucis commented Sep 24, 2021

You could just /// <reference types="custom-lib-module" /> in any file included in your project though?

You can, yes, but this requires per-file inclusion, which is much less convenient than a project-level option.

@delucis
Copy link
Author

delucis commented Sep 24, 2021

A couple more thoughts regarding this approach.

If this were supported, perhaps the package.json resolution step in #45771 would be superfluous. Instead, tsconfig might include "lib": ["npm:@types/web"] or something similar?

As an additional use case side note, I'm also thinking of the utility here for editor tooling for those less familiar with TS. If someone can get TS's autocompletion, hints etc with a standard shared config (potentially preconfigured in a domain-specific IDE), that would be nice. That's another mark against triple-slash directives.

@andrewbranch
Copy link
Member

If this were supported, perhaps the package.json resolution step in #45771 would be superfluous.

No—the reason the package.json thing is important is that you need every existing reference to /// <reference lib="dom" /> to point to node_modules/@types/web. You can add node_modules/@types/web to your program and not specify "lib": ["dom"] today, but you’re screwed as soon as some other types package says /// <reference lib="dom" />.

@delucis
Copy link
Author

delucis commented Sep 24, 2021

Ah, right! Yes, that makes sense.

@andrewbranch
Copy link
Member

Anyway, to your point about not liking "types" or triple-slash references, I think "include" addresses your concerns about each of those? You’d have to specify node_modules as part of the path, which is unattractive, but not problematic as far as I know: "include": ["node_modules/custom-lib-module"]

@delucis
Copy link
Author

delucis commented Sep 24, 2021

In my experience, include can complicate some set-ups and is not ideal in tsconfig files that are intended to be shared across projects. If a shared tsconfig is extended with a new include, that overwrites the shared include right? And you probably have to extend include to pick up the files in the project extending the shared tsconfig.

custom-lib-module/tsconfig.json
{
  "include": ["./lib"],
  // other compiler options etc.
}
consumer/tsconfig.json
{
  "extends": "custom-lib-module/tsconfig.json",
  "include": [
    "src/**/*"
    // and also whatever is in custom lib’s "include"
  ]
}

@delucis
Copy link
Author

delucis commented Sep 24, 2021

I’m not trying to be difficult here — I do get that this is kind of supported and I’m just pushing for a slightly cleaner/simpler/more shareable way of doing this, so I totally get if there’s no bandwidth for something like this.

@orta
Copy link
Contributor

orta commented Sep 24, 2021

I think this can just be solved pretty well with the current tools. We ship a bunch of 'import redirect'-y files in lib which will never change:

es5.full.d.ts

/// <reference lib="es5" />
/// <reference lib="dom" />
/// <reference lib="webworker.importscripts" />
/// <reference lib="scripthost" />

If you shipped:

"@typescript/lib-es5": "npm:my-thing"

All you would need is:

full.d.ts:

/// <reference lib="es5" />
/// <reference lib="dom" />
/// <reference lib="webworker.importscripts" />
/// <reference lib="scripthost" />

type ABC = {
  xcv: string
}

Then it would correctly override just the ES5 wrapped file, not touch any of the actual imports and add your own in the process as globals in any project (with that dependency set up)

Though I can empathize with the idea that there could be a lookup for @typescript/globals in node projects. It's an interesting idea.

@delucis
Copy link
Author

delucis commented Sep 24, 2021

OK, cool, that‘s kind of what I meant by “squatting” on a standard lib name, but reframed like this, perhaps that’s actually an intended rather than hacky use — you’re overriding/augmenting an existing lib, so that does fall into the #45771 use case. The fact this requires two configuration points across separate files that need to be kept in sync does still introduce more friction than I’d like, and the fact that tsconfig doesn’t clearly show the actual lib in use may be a source of confusion, but you can’t have everything in life 😃.

Thanks for taking the time to consider this anyway!

@delucis delucis closed this as completed Sep 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants