Skip to content

Support custom/non-vendor modules for lib #45959

Closed
@delucis

Description

@delucis

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.

Activity

DanielRosenwasser

DanielRosenwasser commented on Sep 23, 2021

@DanielRosenwasser
Member

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

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

delucis commented on Sep 23, 2021

@delucis
Author

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

andrewbranch commented on Sep 24, 2021

@andrewbranch
Member

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

delucis

delucis commented on Sep 24, 2021

@delucis
Author

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

delucis commented on Sep 24, 2021

@delucis
Author

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

andrewbranch commented on Sep 24, 2021

@andrewbranch
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

delucis commented on Sep 24, 2021

@delucis
Author

Ah, right! Yes, that makes sense.

andrewbranch

andrewbranch commented on Sep 24, 2021

@andrewbranch
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

delucis commented on Sep 24, 2021

@delucis
Author

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

delucis commented on Sep 24, 2021

@delucis
Author

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

orta commented on Sep 24, 2021

@orta
Contributor

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

delucis commented on Sep 24, 2021

@delucis
Author

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @orta@delucis@DanielRosenwasser@andrewbranch

        Issue actions

          Support custom/non-vendor modules for `lib` · Issue #45959 · microsoft/TypeScript